适配器模式和代理模式比较专题1
设计模式—适配器模式
适配器模式和代理模式是二个比较容易混淆的模式,我想谈一下这两个模式的差别,不过我先分别介绍一下这二个模式,然后再做比较,我想这样大家可能会比较容易理解,对于不懂这两个模式的人来说也多个了解的机会。
适配器说通俗点就是把一个东西包装一下变成另外一个东西,为什么要包装而不直接就用这个东西呢?呵呵,如果能直接用就犯不着适配了,要适配当然就是由于某些原因你用不了当前这个东西。最容易理解的就是电器的例子,比如你在中国买的电器使用电压是220V,结果你跑到国外去了,国外提供的电压是110V,问题就来了,你必须使用的是220V的,国外提供给你的却只有110V的,所以你根本就用不了,除非你能够将110V的转化成为220V才能行。此时适配器就排上用场了,你使用一个转压器不就可以把110V专成220V了吗?对于程序设计亦然。
下面举一个例子,假如你开始做一个项目的时候你需要写一个集合的枚举接口如下:
public interface Enumeration
{
bool HasMoreElement();
object nextElement();
}
调用的方法如下:
public void BeforeDisplay(Enumeration e)
{
while (e.HasMoreElement())
{
e.nextElement();
}
}
后来由于某一种原因(可能是代码重构、或者类库升级),你定义了另外一个新的集合枚举接口如下:
public interface Iterator
{
bool MoveNext();
object Current();
void Reset();
}
使用新的接口调用方法如下:
public void OldDisplay(Iterator e)
{
while (e.MoveNext())
{
e.Current();
}
}
现在如果要求新的方法都只使用新的接口一切都很顺利,但是由于原来的很多方法用的仍然是旧的接口,而由于逻辑的重用或者 为了升级后类库的向前兼容,你需要将当前的新接口Iterator转换成旧的接口Enumeration以调用原来的方法,这时候就需要我们写一个适配器。
如何编写适配器?由于我们需要用的是Enumeration接口,所以适配器必须是Enumeration的,即必须继承自Enumeration;接着想我们需要利用新的Iterator做业务,简单点就是我们需要用Iterator中的方法,所以最容易想到的一个方法就是拥有一个Iterator的实例,直接调用该实例的方法实现Enumeration接口不就可以了吗?(如果Iterator是个具体的类,我们还可以再继承该类,来个双重继承,利用该具体类的方法实现Enumeration接口,效果一致)
示例代码如下:
public class Itermeration:Enumeration
{
private Iterator it;
public Itermeration(Iterator it)
{
this.it=it;
}
public bool HasMoreElement()
{
return it.MoveNext();
}
public object nextElement()
{
return it.Current();
}
}
注意:由于我们需要将新接口Iterator转换成旧的接口Enumeration,所以新的类必须继承旧的接口Enumeration,将传入的Iterator转换成Enumeration接口。这样调用方法如下:
public void Display(Iterator e)
{
BeforeDisplay(new Itermeration(e));
//此处将Iterator转化为Itermeration,而Itermeration又是继承自Enumeration,所以实际上就是将Iterator转化为Enumeration
}
注意:我们为了将Iterator转化成Enumeration,采用的方式是在他们之间增加了一层,使用Itermeration类来转化,这是面向对象设计中抽象的一个主要思想,贯穿很多设计模式。
适配器模式有两种,我现在举的这个例子是对象的适配器模式,还有一种是类的适配器模式(对应上边括弧中的注释),这两种方式网上介绍的已经太多,我这里就不再赘述,当然现实中以对象的适配器模式使用最多,这也是为什么我举这种类型例子的原因。
其实适配器的思想是很容易理解的,很多人觉得困惑的原因常常不是他们不知道什么是适配器,而是他们联系自己曾有的经验,找不到要这么做的理由,所以内心深处总是对这么做感觉疑惑,当然很多其他的模式也是如此。
那到底什么时候需要用适配器呢?一个根本的理由就是系统需要使用现有的类,但是这个类的接口不符合当前的要求。
注意我这里说的是根本理由,因为这个理由是适配器出现的致命原因,由于这个理由出现了适配器,然后我们仔细揣摩出现后的适配器突然就发现他还有其它的好处,也就冒出了其它的理由。我强调这个的主要原因就是因为很多人开始看一篇文章描述觉得好像是这么回事,结果又看其它人的文章反而觉得越来越迷糊,实际上很大程度上的原因是很多文章往往为了强调全面而花了很多笔墨去写那些后来想起来的好处,而对根本理由轻轻带过,导致很多人误以为导出这种模式的原因是为了使用后来这些好处,结果就越搅越迷糊了。
这里我给出另外一个使用理由,如果你看不太懂没有关系,完全可以忽略不看。
另一个理由就是我们系统中有很多彼此不大关联的类,而且这些类的接口都非常简单,(注意是接口都非常简单,如果都比较复杂用这种方法就是没事找事)。现在我想建立一个可以重复使用的类来跟这些简单类打交道,于是就使用适配,个人认为纯粹是为了方便。