设计模式之适配器模式

自从上次写过关于状态模式的文章之后,已经很久没有写过设计模式的文章了,主要是因为不想为了谈设计模式而谈设计模式。然而,最近用到了Adapter模式,然后突有感想就想将其记录下来。

我想先不管Adapter模式的类图结构,先看一下这样一个问题(模式也来源于生活,我们现在反过来从问题中体会前辈的精华之所在,别有一番滋味啊):见过电脑上PS/2接口吗?我想大家都见过吧(到目前为止我还见有同学的电脑上有这种接口)。如果是有USB和PS/2两种接口还好说,像我的电脑现在只有USB接口(说到这个接口,让我想起面向对象的interface,前辈们命名不是乱来的哦)。现在有一款MP2(不要惊讶,真的在MP3之前有MP2,但这不是重点)PS/2接口,想要插在我电脑上。好了,没办法了。其实我们不管程序怎么写,你在实际生活中会怎么做呢?肯定找个PS/2-USB的转化口啊,其实就是一个适配器,有了它我们的Mp2就能在电脑上读写了。当然我们还有FlashDisk和Mp3Player了,它们自然用USB接口了。现在我们先别找那个适配器了,我们主要是来谈Adapter模式的,还是先看看程序实现:

现在有三个项目,第一个是类库项目叫MyStorage,里面有一个接口和两个类,具体我就不再说了,看代码很简单。

IStorage.cs

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyStorage { public interface IStorage { void Read(); void Write(); } }

FlashDisk.cs

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyStorage { public class FlashDisk:IStorage { #region IStorage 成员 public void Read() { Console.WriteLine("Read Message to Mp4Player!"); } public void Write() { Console.WriteLine("Write Message from Mp4Player!"); } #endregion } }

Mp4Player.cs

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyStorage { public class Mp4Player:IStorage { #region IStorage 成员 public void Read() { Console.WriteLine("Read Message to Mp4Player!"); } public void Write() { Console.WriteLine("Write Message from Mp4Player!"); } #endregion } }

代码很简单,将Mp4和FlashDisk都抽象成了存储设备,都可以进行读写。可是关键我们Mp2,怎么办?先看它的代码,在另一个类库项目中。

IOldStorage.cs

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyOldStorage { public interface IOldStorage { void ReadMessage(); void WirteMessage(); } }

Mp2Player.cs

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyOldStorage { public class Mp2Player:IOldStorage { #region IOldStorage 成员 public void ReadMessage() { Console.WriteLine("Read Message to Mp2Player!"); } public void WirteMessage() { Console.WriteLine("Write Message from Mp2Player!"); } #endregion } }

这个类库中放的都是老设备,接口和原来不同。而我们现在的电脑已经固定了,没办法再换接口了。看看我们第三个工程,是一个控制台应用程序。

先看看我们的电脑,注意它的接口是IStorage,其他的可不行啊。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyStorage; namespace Adapter { class Computer { private IStorage storage; public Computer(IStorage storage) { this.storage = storage; } public void ReadInfo() { storage.Read(); } public void WriteInfo() { storage.Write(); } } }

然后看看如何使用,在Programe.cs中

using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyStorage; using MyOldStorage; namespace Adapter { class Program { static void Main(string[] args) { IStorage storage = new FlashDisk(); Computer computer = new Computer(storage); computer.ReadInfo(); } } }

好了,到现在为止使我们现有设备,不能够正常接入Mp2Player,怎么办啊?去买个适配器吧。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyStorage; using MyOldStorage; namespace Adapter { class Mp2PlayerAdapter:Mp2Player,IStorage { #region IStorage 成员 public void Read() { this.ReadMessage(); } public void Write() { this.WirteMessage(); } #endregion } }

有了它就好办了,我们插上试试。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyStorage; using MyOldStorage; namespace Adapter { class Program { static void Main(string[] args) { IStorage storage = new Mp2PlayerAdapter(); Computer computer = new Computer(storage); computer.ReadInfo(); } } }

哦,成功了!再回过头来我们的适配。

我们的适配器实现了IStorage接口,当然符合Computer参数类型IStorage了,除此之外它还继承了Mp2Player,也就可以用Mp2Player相应的方法了。有点太简单了吧O(∩_∩)O~,来看看类图吧。

类图结构比较简单,Adaptee由于同Target接口不同,所以为了适应Target新增加了Adapter类,而这个类需要同时继承和实现Adaptee和Target。但是这样一来就违背了面向对象中类的单一职责原则,Adapter除了有Adaptee的特性还具有Target的特性,那么怎么办呢?先看另一组类图:

如果这两幅图不放在一起,或许真的很难看出有什么不同,但事实上我们已经将继承关系改成了组合,这也是适配器模式的另一种形式叫对象适配器,上一种叫类适配器。而且可以告诉大家第二种比第一种更好。为什么呢?

因为首先如果我们除了Mp2Player还有Mp1Player怎么办?还有其他PS/2的存储设备怎么办?用类适配器的话还需要再写一个适配器,显然不太好;除此之外如果用类适配器的话,适配器依赖于具体的Adptee(例如上面我们的适配器就依赖于Mp2Player),而对象适配器则不需要。

好了,有了类图实现对象适配器就是体力劳动了。

我们的适配器通用性更强了,我们取名为OldStorageAdapter吧,只要PS/2口的都能用。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyStorage; using MyOldStorage; namespace Adapter { class OldStorageAdapter:IStorage { private IOldStorage oldStorage; public OldStorageAdapter(IOldStorage oldStorage) { this.oldStorage = oldStorage; } #region IStorage 成员 public void Read() { oldStorage.ReadMessage(); } public void Write() { oldStorage.WirteMessage(); } #endregion } }

完成之后,插到我的computer上试试吧

using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyStorage; using MyOldStorage; namespace Adapter { class Program { static void Main(string[] args) { IStorage storage = new OldStorageAdapter(new Mp2Player()); Computer computer = new Computer(storage); computer.ReadInfo(); } } }

不错,很方便,而且通用。

到了这里适配器模式我们已经说完了,相信聪明的你肯定都明白了,但是我觉得学习这类东西需要仔细琢磨,看例子都很简单,经过认真思考过之后才能够真正有所悟。

源代码下载:Adapter.rar

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值