适配(转换)的概念无处不在......
适配,即在不改变原有实现的基础上,将原先不兼容的接口转换为兼容的接口。
例如:二转换为三箱插头,将高电压转换为低电压等。
动机(Motivate):
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。
那么如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?这就是本文要说的Adapter 模式。
意图(Intent):
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
-------《设计模式》GOF
结构(Struct):
图1:对象适配器
图2:类适配器
生活中的例子:
适用性:
1.系统需要使用现有的类,而此类的接口不符合系统的需要。
2.想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。这些源类不一定有很复杂的接口。
3.(对对象适配器而言)在设计里,需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。
示意性代码实例:
1 interface IStack
2 {
3 void Push(object item);
4 void Pop();
5 object Peek();
6 }
1 //对象适配器(Adapter与Adaptee组合的关系)
2 public class Adapter : IStack //适配对象
3 {
4 ArrayList adaptee;//被适配的对象
5 public Adapter()
6 {
7 adaptee = new ArrayList();
8 }
9 public void Push(object item)
10 {
11 adaptee.Add(item);
12 }
13 public void Pop()
14 {
15 adaptee.RemoveAt(adaptee.Count - 1);
16 }
17 public object Peek()
18 {
19 return adaptee[adaptee.Count - 1];
20 }
21 }
类适配器
1 public class Adapter :ArrayList, IStack
2 {
3 public void Push(object item)
4 {
5 this.Add(item);
6 }
7 public void Pop()
8 {
9 this.RemoveAt(this.Count - 1);
10 }
11 public object Peek()
12 {
13 return this[this.Count - 1];
14 }
15 }
Adapter模式的几个要点:
Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。
GOF23定义了两种Adapter模式的实现结构:对象适配器和类适配器。但类适配器采用“多继承”的实现方式,带来不良的高耦合,所以一般不推荐使用。对象适配器采用“对象组合”的方式,更符合松耦合精神。
Adapter模式可以实现的非常灵活,不必拘泥于GOF23中定义的两种结构。例如,完全可以将Adapter模式中的“现存对象“作为新的接口方法参数,来达到适配的目的。
Adapter模式本身要求我们尽可能地使用”面向接口的编程"风格,这样才能在后期很方便的适配。
.NET框架中的Adapter应用:
(1)在.Net中复用com对象:
Com 对象不符合.net对象的接口
使用tlbimp.exe来创建一个Runtime Callable Wrapper(RCW)以使其符合.net对象的接口。
(2).NET数据访问类(Adapter变体):
各种数据库并没有提供DataSet接口
使用DBDataAdapter可以将任何各数据库访问/存取适配到一个DataSet对象上。
(3)集合类中对现有对象的排序(Adapter变体);
现有对象未实现IComparable接口
实现一个排序适配器(继承IComparer接口),然后在其Compare方法中对两个对象进行比较。