1. 意图
将一个类的接口转换成客户希望的另外一个接口。A d a p t e r模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
2.适用性
以下情况使用A d a p te r模式
• 你想使用一个已经存在的类,而它的接口不符合你的需求。
• 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
• (仅适用于对象A d a p t e r)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
3.结构类图
4.参与者
• Ta r g e t
— 定义C l i e n t使用的与特定领域相关的接口。
• C l i e n t
— 与符合Ta rg e t接口的对象协同。
• A d a p t e e
— 定义一个已经存在的接口,这个接口需要适配。
• A d a p t e r
— 对A d a p t e e的接口与Ta rg e t接口进行适配
5.协作
• Client在A d a p t e r实例上调用一些操作。接着适配器调用A d a p t e e的操作实现这个请求。
类适配器和对象适配器有不同的权衡。
类适配器:
• 用一个具体的A d a p t e r类对A d a p t e e和Ta rg e t进行匹配。结果是当我们想要匹配一个类以
及所有它的子类时,类A d ap t e r将不能胜任工作。
• 使得A d a p t e r可以重定义A d a p t e e的部分行为,因为A d a pt e r是A d a p t e e的一个子类。
• 仅仅引入了一个对象,并不需要额外的指针以间接得到a d a p t e e。
对象适配器:
• 允许一个A d a p t e r与多个A d a p t e e—即A d a p t e e本身以及它的所有子类(如果有子类的话)—同时工作。A d a p t er也可以一次给所有的A d a p t e e添加功能。
• 使得重定义A d a p t e e的行为比较困难。这就需要生成A d a p t e e的子类并且使得A d a p t e r引用这个子类而不是引用A d a p t e e本身。
6.实现
1) 使用C + +实现适配器类 在使用C + +实现适配器类时, A d a p t e r类应该采用公共方式继承Ta rg e t类,并且用私有方式继承A d a p t e e类。因此, A d a p t e r类应该是Ta rg e t的子类型,但不是A d a p t e e的子类型。
2) 可插入的适配器 有许多方法可以实现可插入的适配器。
7.相关模式
模式B r i d g e 的结构与对象适配器类似,但是B r i d g e模式的出发点不同: B r i d g e目的是将接口部分和实现部分分离,从而对它们可以较为容易也相对独立的加以改变。而A d a p t e r则
意味着改变一个已有对象的接口。
D e c o r a t o r 模式增强了其他对象的功能而同时又不改变它的接口。因此d e c o r a t o r对应用程序的透明性比适配器要好。结果是d e c o r a t o r支持递归组合,而纯粹使用适配器是不可能
实现这一点的。
模式P r o x y 在不改变它的接口的条件下,为另一个对象定义了一个代理。
具体用C#实现的类图:
所有类的源码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SimpleAdaptorPattern { //申明客户期待的接口或者抽象类Target abstract public class Taiget { public abstract void Request(); } //申明要适配的类Adaptee,也就是与期望不相符合的类 public class Adaptee { public void SpecificRequest() { Console.WriteLine("这是特殊请求类,执行的结果!"); } } //申明适配器类Adapter,用对象适配器的方法,即使用的是一个指向Adaptee的引用。 public class Adaptor : Taiget { private Adaptee MyAdaptee; //这就是私有的引用。 public override void Request() { //throw new NotImplementedException(); if (MyAdaptee == null) MyAdaptee = new Adaptee(); MyAdaptee.SpecificRequest(); //真正需要执行的操作。 } } //客户端执行的代码 class Program { static void Main(string[] args) { Taiget target = new Adaptor(); target.Request(); //这就是客户端执行的是可见的接口。 Console.ReadKey(); } } }
运行截图:
直观的关系图: