设计模式之适配器模式与外观模式

适配器模式

适配器模式就是将一个接口转化成另一个接口。

一个常见的例子是插头转换器

我们知道英式插头长这样:

而国内的插头一般是这样的

这时候,你就需要一个转换插头了

而适配器的工作就像是一个转换插头。你不需要从新买一个电器,也不用换一个插孔,只需要一个转换器即可。

假设已有一个软件系统,你希望它能和新的厂商类库搭配使用,但是这个新厂商设计出来的接口,不同于旧厂商的接口。

你不想改变现有的代码,也不能改变厂商的代码,于是你可以写一个类,将新厂商接口转成你所希望的接口。

情景:

首先你有一个鸭子接口(这书有毒啊啊啊这都什么破例子)

有一个鸭子的子类

MallardDuck @Override </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; quack() { System.out.println(</span>"Quack"<span style="color: #000000;"&gt;); } @Override </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; fly() { System.out.println(</span>"I'm flying"<span style="color: #000000;"&gt;); }

}

然后现在有一只火鸡

<div class="cnblogs_code">

  WildTurkey @Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; gobble() {
    System.out.println(</span>"Gobble gobble"<span style="color: #000000;"&gt;);
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; fly() {
    System.out.println(</span>"I'm flying a short diatance"<span style="color: #000000;"&gt;);
}

}

因为你想要鸭子,鸭子不够用了,但是我们有火鸡,于是你决定为火鸡写一个配适器,偷偷地假装它们是鸭子。。。。

当需要鸭子叫的时候,就让火鸡叫,当需要鸭子飞的时候,就让火鸡飞。火鸡飞的距离短,所以还要多飞几次。

TurkeyAdapter </span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; TurkeyAdapter(Turkey turkey) { </span><span style="color: #0000ff;"&gt;this</span>.turkey =<span style="color: #000000;"&gt; turkey; } </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; quack() { turkey.gobble(); } </span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; fly() { </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 火鸡飞行距离短 要连续飞五次才能对应鸭子的飞行</span> <span style="color: #0000ff;"&gt;for</span> (<span style="color: #0000ff;"&gt;int</span> i = 0; i < 5; ++<span style="color: #000000;"&gt;i) { turkey.fly(); } }

}

然后测试一下:

= WildTurkey turkey </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; WildTurkey(); Duck turkeyAdapter </span>= <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; TurkeyAdapter(turkey); System.out.println(</span>"The turkey says..."<span style="color: #000000;"&gt;); turkey.gobble(); turkey.fly(); System.out.println(</span>"\nThe Duck says..."<span style="color: #000000;"&gt;); testDuck(duck); System.out.println(</span>"\nThe TurkeyAdapter says..."<span style="color: #000000;"&gt;); testDuck(turkeyAdapter); } </span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;static</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; testDuck(Duck duck) { duck.quack(); duck.fly(); }

}

输出:

'm flying a short diatance 'm flying 'm flying a short diatance I'm flying a short diatance I'm flying a short diatance I'm flying a short diatance I'm flying a short diatance

我们就可以把火鸡当成鸭子了~(真·有毒。。。。

类图:

上面的类图表现的是“对象”适配器,还有一种适配器,被称作“类”适配器,需要多重继承才能实现,所以在Java中是不可能的。

现实世界一个简单的适配器。

在早期的集合实现如Vector,Stack,HashTable都实现了一个elements()的方法,该方法会返回一个Enumeration,这个接口可以逐一走过集合内的每一个元素。

而新的集合类,使用Iterator来遍历集合。

现在,将枚举适配到迭代器。

<span style="color: #0000ff;">public <span style="color: #0000ff;">class EnumerationIterator <span style="color: #0000ff;">implements<span style="color: #000000;"> Iterator {

Enumeration enu;

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; EnumerationIterator(Enumeration enu) {
    </span><span style="color: #0000ff;"&gt;this</span>.enu =<span style="color: #000000;"&gt; enu;
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;boolean</span><span style="color: #000000;"&gt; hasNext() {
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; enu.hasMoreElements();
}

@Override
</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; Object next() {
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; enu.nextElement();
}

</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; remove() {
    </span><span style="color: #0000ff;"&gt;throw</span> <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; UnsupportedOperationException();
}

}

反过来也可以将迭代器适配到枚举

<span style="color: #0000ff;">public <span style="color: #0000ff;">class IteratorEnumeration <span style="color: #0000ff;">implements<span style="color: #000000;"> Enumeration {
Iterator iterator;

</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; IteratorEnumeration(Iterator iterator) {
    </span><span style="color: #0000ff;"&gt;this</span>.iterator =<span style="color: #000000;"&gt; iterator;
}

@Override
</span><span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;boolean</span><span style="color: #000000;"&gt; hasMoreElements() {
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; iterator.hasNext();
}

@Override
</span><span style="color: #0000ff;"&gt;public</span><span style="color: #000000;"&gt; Object nextElement() {
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; iterator.next();
}

}

测试一下:

<span style="color: #0000ff;">public <span style="color: #0000ff;">class<span style="color: #000000;"> ArrayListEnumTest {
<span style="color: #0000ff;">public
<span style="color: #0000ff;">static
<span style="color: #0000ff;">void<span style="color: #000000;"> main(String[] args) {
ArrayList list = <span style="color: #0000ff;">new<span style="color: #000000;"> ArrayList();
list.add("适"<span style="color: #000000;">);
list.add("配"<span style="color: #000000;">);
list.add("器"<span style="color: #000000;">);
list.add("模"<span style="color: #000000;">);
list.add("式"<span style="color: #000000;">);
Iterator iterator =<span style="color: #000000;"> list.iterator();
Enumeration ei = <span style="color: #0000ff;">new<span style="color: #000000;"> IteratorEnumeration(iterator);
showListByEnum(ei);
}

</span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 一些遗留的“客户代码”仍然使用依赖于枚举接口</span>
<span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;static</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; showListByEnum(Enumeration enumeration) {
    </span><span style="color: #0000ff;"&gt;while</span><span style="color: #000000;"&gt; (enumeration.hasMoreElements()) {
        System.out.print(enumeration.nextElement());
    }
}

}

外观模式

情景:当你需要看一场电影的时候,你可能需要调灯光放屏幕打开投影机选择模式……每一次都是一样的步骤,等结束的时候,又是一系列繁琐的动作。

如果提供一个简单的类,能够一下就完成这一系列工作就好了。

这时就需要用外观模式,将一系列子类包装起来,提供一个简单的接口,来替代访问一系列子系统的接口。

  • 外观模式不只简化了接口,也将客户从组件的子系统中解耦。
  • 外观模式和适配器模式可以包装许多类,但外观的意图是简化接口,而适配器的意图是将接口转换成不同接口。

原谅自己只能写一个拙劣的例子,折叠掉。。。

类图:

这个原则希望我们在设计中,不要让太多的类耦合在一起,免得修改系统中的一部分,会影响到其他部分。

怎么才能避免这样?这个原则提供了一些方针:就任何对象而言,在该对象的方法内,我们只应调用属于以下范围的方法:

  • 该对象本身
  • 被当做方法的参数而传递进来的对象
  • 此方法所创建或实例化的任何对象
  • 对象的任何组件

举个栗子:

不使用这个原则:

=

使用这个原则:

应用此原则时,在气象站中加一个方法,用来向温度计请求温度。这可以减少我们所依赖的类的数目。

综上:

当需要使用一个现有的类而其接口并不符合你的需求时,就使用适配器。

当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结