本帖最后由 惜 于 2019-1-5 10:45 编辑
结构模式(Structural Pattern)描述如何将类或者对象结合在一起形成更大的结构。结构模式描述两种不同的
东西:类与类的实例。根据这一点,结构模式可以分为类的结构模式和对象的结构模式。
后续内容将包括以下结构模式:
 适配器模式(Adapter): Match interfaces of different classes
 合成模式 (Composite): A tree structure of simple and composite objects
 装饰模式 (Decorator): Add responsibilities to objects dynamically
 代理模式 (Proxy): An object representing another object
 享元模式 (Flyweight): A fine-grained instance used for efficient sharing
 门面模式 (Facade): A single class that represents an entire subsystem
 桥梁模式 (Bridge): Separates an object interface from its implementation
一 、 适配器 (Adapter ) 模式
适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作。
名称由来
这很像变压器(Adapter),变压器把一种电压变换成另一种电压。美国的生活用电电压是 110V,而中国的电
压是 220V。如果要在中国使用美国电器,就必须有一个能把 220V 电压转换成 110V 电压的变压器。这个变压
器就是一个 Adapter。
Adapter 模式也很像货物的包装过程:被包装的货物的真实样子被包装所掩盖和改变,因此有人把这种模式叫
做包装(Wrapper)模式。事实上,大家经常写很多这样的 Wrapper 类,把已有的一些类包装起来,使之有能
满足需要的接口。
适配器模式的两种形式
适配器模式有类的适配器模式和对象的适配器模式两种。我们将分别讨论这两种 Adapter 模式。
二 、 类的 Adapter 模式的结构
由图中可以看出,Adaptee 类没有 Request 方法,而客户期待这个方法。为了使客户能够使用 Adaptee 类,
提供一个中间环节,即类 Adapter 类,Adapter 类实现了 Target 接口,并继承自 Adaptee,Adapter 类的
Request 方法重新封装了 Adaptee 的 SpecificRequest 方法,实现了适配的目的。
因为 Adapter 与 Adaptee 是继承的关系,所以这决定了这个适配器模式是类的。
该适配器模式所涉及的角色包括:
目标(Target)角色:这是客户所期待的接口。因为 C#不支持多继承,所以 Target 必须是接口,不可以是类。
源(Adaptee)角色:需要适配的类。
适配器(Adapter)角色:把源接口转换成目标接口。这一角色必须是类
三 、 类的 Adapter 模式示意性实现
下面的程序给出了一个类的 Adapter 模式的示意性的实现:
[C#] 纯文本查看 复制代码 using System;
namespace ConsoleApplication1
{
/// <summary>
/// 我们要实现的接口
/// </summary>
interface ITarget
{
// Methods
void Request();
}
/// <summary>
/// 我们要封装的类
/// </summary>
class Adaptee
{
// Methods
public void SpecificRequest()
{
Console.WriteLine("Called SpecificRequest()");
}
}
/// <summary>
/// 实际封装实现的类
/// </summary>
class Adapter : Adaptee, ITarget
{
// Implements ITarget interface
public void Request()
{
// Possibly do some data manipulation
// and then call SpecificRequest
this.SpecificRequest();
}
}
/// <summary>
/// 调用
/// </summary>
public class Client
{
public static void Main(string[] args)
{
// Create adapter and place a request
ITarget t = new Adapter();
t.Request();
}
}
}
四 、 对象的 Adapter 模式的结构 :
从图中可以看出:客户端需要调用 Request 方法,而 Adaptee 没有该方法,为了使客户端能够使用 Adaptee
类,需要提供一个包装(Wrapper)类 Adapter。这个包装类包装了一个 Adaptee 的实例,从而将客户端与
Adaptee 衔接起来。由于 Adapter 与 Adaptee 是委派关系,这决定了这个适配器模式是对象的。
该适配器模式所涉及的角色包括:
目标(Target)角色:这是客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
源(Adaptee)角色:需要适配的类。
适配器(Adapter)角色:通过在内部包装(Wrap)一个 Adaptee 对象,把源接口转换成目标接口。
五 、 对象的 Adapter 模式示意性实现
下面的程序给出了一个类的 Adapter 模式的示意性的实现:
[C#] 纯文本查看 复制代码 // Adapter pattern -- Structural example
using System;
namespace ConsoleApplication1
{
/// <summary>
/// 我们要继承的基类
/// </summary>
class Target
{
/// <summary>
/// 虚方法 在派生类中 重写
/// </summary>
public virtual void Request()
{
// Normal implementation goes here
}
}
/// <summary>
/// 我们实现重写封装的类
/// </summary>
class Adapter : Target
{
// 实列对象
private Adaptee adaptee = new Adaptee();
// 重写基类的方法
public override void Request()
{
// Possibly do some data manipulation
// and then call SpecificRequest
adaptee.SpecificRequest();
}
}
/// <summary>
/// 我们要封装的类
/// </summary>
class Adaptee
{
// Methods
public void SpecificRequest()
{
Console.WriteLine("Called SpecificRequest()");
}
}
/// <summary>
/// 调用
/// </summary>
public class Client
{
public static void Main(string[] args)
{
// Create adapter and place a request
Target t = new Adapter();
t.Request();
}
}
}
六 、 在什么情况下使用适配器模式
在以下各种情况下使用适配器模式:
1、 系统需要使用现有的类,而此类的接口不符合系统的需要。
2、 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的
类一起工作。这些源类不一定有很复杂的接口。
3、 (对对象适配器而言)在设计里,需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一
个子类做一个适配器,而这不太实际。
七 、 一个实际应用 Adapter 模式的例子
下面的程序演示了 Class Adapter 与 Object Adapter 的应用。
[C#] 纯文本查看 复制代码 // Example of implementing the Adapter pattern
using System;
/// <summary>
/// 我们要实现的接口
/// </summary>
public interface ICar
{
void Drive();
}
/// <summary>
/// 继承 实现 ICar
/// </summary>
public class CToyota : ICar
{
public void Drive()
{
Console.WriteLine("Vroom Vroom, we're off in our Toyota ");
}
}
/// <summary>
///需要封装的类
/// </summary>
public class CCessna
{
public void Fly()
{
Console.WriteLine("Static runup OK, we're off in our C172 ");
}
}
/// <summary>
/// 我们继承了CCessna ICar (类的Adapter)
/// </summary>
public class CDrivableCessna : CCessna, ICar
{
/// <summary>
/// 在这里实现了Drive 并在Drive里面 调用 CCessna =>Fly
/// </summary>
public void Drive() { base.Fly(); }
}
/// <summary>
/// 继承 实现 实例化后调用(对象的Adapter)
/// </summary>
public class CDrivableCessna2 : ICar
{
private CCessna m_oContained;
public CDrivableCessna2()
{
m_oContained = new CCessna();
}
public void Drive() { m_oContained.Fly(); }
}
/// <summary>
/// 调用
/// </summary>
public class Client
{
public static void Main(string[] args)
{
ICar oCar = new CToyota();
Console.Write("Class Adapter: Driving an Automobile ");
oCar.Drive();
oCar = new CDrivableCessna();
Console.Write("Driving a Cessna ");
oCar.Drive();
oCar = new CDrivableCessna2();
Console.Write(" Object Adapter: Driving a Cessna ");
oCar.Drive();
}
}
|