适配器模式(Adapter Pattern)
- 适配器模式简述:
定义:将一个类的接口转化成客户希望的另一个接口,适配器模式让那些接口不兼容的类可以一起工作。别名(包装器[wrapper]模式)
它属于创建型模式的成员,何为创建型模式:就是关注如何将现有类或对象组织在一起形成更大的结构。由于系统中存在类和对象,所以存在两种结构型模式:类结构型模式(关注类的组合,由多个类组成一个更大的系统,一般只有继承关系和实现关系)、对象结构型模式(关注类和对象的组合,通过关联关系,在一个类中定义另一个类的对象,然后通过该对象调用相关方法)。
适配器,适配器,笔记本要用的就是电源适配器(ac adapter),没错,有了电源适配器,我们笔记本就能使用本来不能使用的220v的电压了,这也就是电源适配器的功劳。我们这里也一样,引入适配器模式以兼容某些结构。
- 适配器模式的结构
结构:
- target(目标抽象类):它定义客户所需的接口(能用的电压),可以是abstract类或接口,也可以是具体类。在类适配器中,只能是接口(单继承)
- adapter(适配器类):可调用另一个接口,作为转化器。,对adaptee和target进行适配,相当于电源适配器。类适配中实现target接口并继承adaptee来实现产生关系,在对象适配器中,继承targer并关联adaptee对象产生联系(如上图)
- adaptee(适配者类):它是被适配的,定义一个已存在的接口,相当于220v电压。一般是一个具体类(有了才能去适配)。
简单分析:
上图是课上老师给的例子,这样理解起来就很容易了。伪装者即适配器类,由于要用到鸭子的方法,所以用火鸡伪装下,它关联鸭子,就可以在内部生成鸭子的对象。即披着鸭子皮的火鸡,让小朋友们误以为是鸭子在表演。
- 缺省适配器模式(default adapter pattern)
定义:缺当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。
结构:
- serviceinterface(适配者接口):在该接口中声明许多方法
- abstractserviceclass(缺省适配器类):核心类,使用空方法实现serviceinteface中的方法,对它实例化无意义
- concrserviceclass(具体业务类):缺省适配器类的子类,直接继承适配器类,根据需要有选择性的实现上述中的某个方法
- 双向适配器
适配器中同时包含对目标类和适配器类的引用,适配者可以通过调用目标类中的方法,目标类也可以通过它调用适配者类中的方法,该适配器即双向适配器
结构:
1 public class adapter : target, adaptee 2 { 3 //同时维持对抽象目标类和适配者的引用 4 private target target; 5 private adaptee adaptee; 6 7 public adapter(target target) 8 { 9 this.target = target; 10 } 11 12 public adapter(adaptee adaptee) 13 { 14 this.adaptee = adaptee; 15 } 16 17 public void request() 18 { 19 adaptee.specificrequest(); 20 } 21 22 public void specificrequest() 23 { 24 target.request(); 25 } 26 }
应用:实现一个双向适配器实例,使得猫(cat)可以学狗(dog)叫(cry()),狗可以学猫捉老鼠(catchmouse())
实现:
1 using system; 2 using system.collections.generic; 3 using system.linq; 4 using system.text; 5 6 namespace 适配器模式 7 { 8 public interface idog 9 { 10 void action(); 11 void wang(); 12 } 13 14 public interface icat 15 { 16 void cry(); 17 void catchmouse(); 18 } 19 20 public class snoopy : idog 21 { 22 public void action() 23 { 24 } 25 26 public void wang() 27 { 28 console.writeline("汪汪的叫......."); 29 } 30 } 31 32 public class tom : icat 33 { 34 public void cry() 35 { 36 } 37 38 public void catchmouse() 39 { 40 console.writeline("捉老鼠....."); 41 } 42 } 43 44 public class adapter : icat, idog 45 { 46 private idog dog; 47 private icat cat; 48 49 public adapter(idog d) 50 { 51 this.dog = d; 52 } 53 54 public adapter(icat c) 55 { 56 this.cat = c; 57 } 58 59 public void cry() 60 { 61 dog.wang(); 62 } 63 64 public void catchmouse() 65 { 66 cat.catchmouse(); 67 } 68 69 public void action() 70 { 71 cat.catchmouse(); 72 } 73 74 public void wang() 75 { 76 dog.wang(); 77 } 78 } 79 80 class program 81 { 82 static void main(string[] args) 83 { 84 //这里猫想学狗叫,实现cry的方法,所以适配者首先是一只猫,它要实现猫的cry的方法, 85 //但适配者是假的,它只能借助狗的方法来实现。 86 icat cat = new adapter(new snoopy()); 87 console.write("cat learn:"); 88 cat.cry(); 89 console.read(); 90 } 91 } 92 93 }
- 适配器模式的优点
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构
- 增加了类的透明性和复用性,提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用
- 灵活性和扩展性非常好
- 类适配器模式:置换一些适配者的方法很方便
- 对象适配器模式:可以把多个不同的适配者适配到同一个目标,还可以适配一个适配者的子类
- 适配器模式的缺点
- 类适配器模式
- 一次最多只能适配一个适配者类,不能同时适配多个适配者
- 适配者类不能为最终类
- 目标抽象类只能为接口,不能为类
- 对象适配器模式
- 对象适配器模式:在适配器中置换适配者类的某些方法比较麻烦
- 适配器模式的适用环境
- 系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码
- 创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作
上一篇: C++中的自定义内存管理
下一篇: PHP对字符串的递增运算分析