适配器模式(Adapter Pattern):
将某个类的接口转换成客户端期望的另一个接口表示,主要的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。如读卡器是作为内存卡和笔记本之间的适配器,需要将内存卡插入读卡器,再将读卡器插入笔记本,这样笔记本就可以读取内存卡了。
适配器模式的主要角色:
1、目标接口(Target):当前系统业务所期待的接口,它可以是抽象类或接口。
2、适配者类(Adaptee):被访问和适配的现存组件库中的组件接口。
3、适配器类(Adapter):转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
适配器模式主要分三类:类适配器模式、对象适配器模式、接口适配器模式(java中使用)。接下来我们来详细介绍下这三种形式。
1、类适配器模式
当前去外地出差,工作繁忙,回到宾馆也不得不工作。当你拿出电脑,准备接电源,卧槽...不支持!!!电源是两孔的,而插座是三孔的,怎么办呢?你会想到去楼下小商店买个转换插座,将三孔插座转成两孔的来用,简直太聪明了。
(以该图代替,原理类似)
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 Computer computer = new Computer(new TwoHoleSocket()); 6 computer.Connect(); 7 // 类适配器的缺点 8 TwoHoleSocket twoHoleSocket = new TwoHoleSocket(); 9 twoHoleSocket.Test(); 10 } 11 } 12 13 internal class Computer 14 { 15 private readonly Transformer transformer; 16 17 public Computer(Transformer transformer) 18 { 19 this.transformer = transformer; 20 } 21 22 public void Connect() 23 { 24 transformer.Transfrom(); 25 Console.WriteLine("连接成功!!!"); 26 } 27 } 28 29 /// <summary> 30 /// 三孔插座Adaptee 31 /// </summary> 32 internal class ThreeHoleSocket 33 { 34 public void Show() 35 { 36 Console.WriteLine("我是三孔插座"); 37 } 38 39 public void Test() 40 { 41 Console.WriteLine("我是多余的"); 42 } 43 } 44 45 /// <summary> 46 /// 转换器Target 47 /// </summary> 48 internal interface Transformer 49 { 50 void Transfrom(); 51 } 52 53 /// <summary> 54 /// 两孔插座Adapter 55 /// </summary> 56 internal class TwoHoleSocket : ThreeHoleSocket, Transformer 57 { 58 public void Transfrom() 59 { 60 base.Show(); 61 Console.WriteLine("转换中。。。。"); 62 Console.WriteLine("哈哈哈,我已经是两孔插座"); 63 } 64 }
分析:对于类适配器来说,Adapter与Adaptee过于耦合,增加了使用成本,且会暴露不必要的方法。
2、对象适配器模式
当手机没电需要充电,你不可能直接使用220V的电压,如果你真这么做了,请注意人身安全及购买一台新机。此时,充电器就起到了转换器的作用,将220V电压转换成手机可使用的5V电压。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Phone phone = new Phone(); 6 phone.charging(new VoltageAdapter(new Voltage220V())); 7 } 8 } 9 10 class Phone 11 { 12 public void charging(Voltage5V voltage5V) 13 { 14 voltage5V.output5V(); 15 } 16 } 17 18 class Voltage220V 19 { 20 public void output220V() 21 { 22 Console.WriteLine("220V"); 23 } 24 } 25 26 interface Voltage5V 27 { 28 void output5V(); 29 } 30 31 class VoltageAdapter : Voltage5V 32 { 33 private readonly Voltage220V voltage220V; 34 35 public VoltageAdapter(Voltage220V voltage220V) 36 { 37 this.voltage220V = voltage220V; 38 } 39 40 public void output5V() 41 { 42 voltage220V.output220V(); 43 Console.WriteLine("5V"); 44 } 45 }
分析:以松耦合的方式实现适配器模式,推荐使用。
3、接口适配器模式(java中使用,c#中能够实现但意义不大)
1 class Program 2 { 3 static void Main(string[] agrs) 4 { 5 Power5VAdapter power5VAdapter = new Power5VAdapter(new AC220()); 6 Console.WriteLine(power5VAdapter.output5V()); 7 } 8 } 9 10 class AC220 11 { 12 public int output220V() 13 { 14 int output = 220; 15 return output; 16 } 17 } 18 19 interface Voltage 20 { 21 int output5V(); 22 int output9V(); 23 int output12V(); 24 int output24V(); 25 } 26 27 abstract class PowerAdapter : Voltage 28 { 29 private readonly AC220 ac220; 30 31 public PowerAdapter(AC220 ac220) 32 { 33 this.ac220 = ac220; 34 } 35 36 public virtual int output12V() 37 { 38 return ac220.output220V(); 39 } 40 41 public virtual int output24V() 42 { 43 return ac220.output220V(); 44 } 45 46 public virtual int output5V() 47 { 48 return ac220.output220V(); 49 } 50 51 public virtual int output9V() 52 { 53 return ac220.output220V(); 54 } 55 } 56 57 class Power5VAdapter : PowerAdapter 58 { 59 private AC220 ac220; 60 61 public Power5VAdapter(AC220 ac220) 62 : base(ac220) 63 { 64 this.ac220 = ac220; 65 } 66 67 public override int output5V() 68 { 69 int output = 0; 70 if (this.ac220 != null) 71 { 72 output = this.ac220.output220V() / 44; 73 } 74 return output; 75 } 76 }
优点:
1、客户端通过适配器可以透明地调用目标接口。
2、复用了现存的类,开发人员不需要修改原有代码而重用现有的适配者类。
3、将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。
缺点:
1、对类适配器来说,更换适配器的实现过程比较复杂。
2、过多的适配器,会让系统零乱,不易整体进行把握。