动机(Motivation)
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是环境要求的接口是这些现存对象不满足的。
如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?
意图(Intent)
将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
结构(Structure):
对象适配器:
类适配器:
代码实现:
1 对象适配器 2 interface IStackable 3 { 4 void Push(object item); 5 object Pop(); 6 object Peek(); 7 } 8 //对象适配器 9 public class MyStack : IStackable//适配对象 10 { 11 ArrayList list;//被适配对象 12 private int _top=-1; 13 public MyStack() 14 { 15 list = new ArrayList(); 16 } 17 public void Push(object item) 18 { 19 list.Add(item); 20 _top++; 21 } 22 23 public object Pop() 24 { 25 _top--; 26 return list[_top+1]; 27 } 28 29 public object Peek() 30 { 31 return list[_top]; 32 } 33 }
1 类适配器 2 //类适配器 3 public class MyStack :ArrayList, IStackable//适配对象 4 { 5 private int _top1=-1; 6 public void Push(object item) 7 { 8 this.Add(item); 9 _top1++; 10 } 11 12 public object Pop() 13 { 14 _top1--; 15 return this[_top1 + 1]; 16 } 17 18 public object Peek() 19 { 20 return this[_top1]; 21 } 22 }
Adapter模式的几个要点:
Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。
GoF23定义了两种Adapter模式的实现结构:对象适配器和类适配器。但类适配器采用“多继承”的实现方式,带来了不良的高耦合,所以一般不推荐使用。对象适配器采用“对象组合”的方式,更符合松耦合精神。
Adapter模式可以实现的非常灵活,不必拘泥于GoF23中定义的两种结构。例如,完全可以将Adapter模式中的“现存对象”作为新的接方法参数,来达到适配的目的。
Adapter模式本身要求我们尽可能地使用“面向接口的编程”风格,这样才能在后期很方便的适配。
1 对于已经存在的类作为被适配对象的代码实现 2 //已经存在的类,被适配对象 3 public class ExistingClass 4 { 5 public void SpecificRequest1() 6 { 7 8 } 9 public void SpecificRequest2() 10 { 11 12 } 13 } 14 15 interface Itarget 16 { 17 void request(); 18 } 19 //另外一个系统 20 public class MySystem 21 { 22 public void Process(Itarget target) 23 { 24 25 } 26 } 27 28 public class Adapter : Itarget 29 { 30 ExistingClass adaptee=new ExistingClass (); 31 32 public void Request() 33 { 34 adaptee.SpecificRequest1(); 35 adaptee.SpecificRequest2(); 36 } 37 }
.NET框架中的Adapter应用:
在.NET中复用COM对象:
--COM对象不符合.NET对象的接口
--使用tlbimp.exe来创建一个Runtime Callable Wrapper(RCW)以使其符合.NET对象的接口。
.NET数据访问类(Adapter变体):
--各种数据库并没有提供DataSet接口
--使用DbDataAdapter可以将任何数据库访问/存取适配到一个DataSet对象上。
集合类中对现有对象的排序(Adapter变体):
--现有对象未实现IComparable接口。
--实现一个排序适配器(继承IComparable接口),然后在其Conpare方法中对两个对象进行比较。
1 排序比较器的代码实现: 2 public int Compare(object x, object y) 3 { 4 Person p1 = (Person)x; 5 Person p2 = (Person)y; 6 if (p1.Age == p2.Age) 7 { 8 return 0; 9 } 10 else if (p1.Age < p2.Age) 11 { 12 return -1; 13 } 14 else 15 { 16 return 1; 17 } 18 }
1 比较对象类 2 class Person 3 { 4 private int _age; 5 6 public int Age 7 { 8 get { return _age; } 9 set { _age = value; } 10 } 11 private string _name; 12 13 public string Name 14 { 15 get { return _name; } 16 set { _name = value; } 17 } 18 public Person(int age, string name) 19 { 20 this.Age = age; 21 this.Name = name; 22 } 23 }
1 主函数的调用 2 static void Main(string[] args) 3 { 4 Person[] list = new Person[] { 5 new Person(12,"ZS"), 6 new Person(10,"ls"), 7 new Person(20,"wz"), 8 new Person(14,"zl") 9 }; 10 Array.Sort(list,new MyCompare()); 11 foreach (var item in list) 12 { 13 Console.Write(item.Name+","); 14 } 15 Console.ReadLine(); 16 }