加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-13 20:55:47 所属栏目:百科 来源:网络整理
导读:适配器模式 适配器模式就是将一个接口转化成另一个接口。 一个常见的例子是插头转换器 我们知道英式插头长这样: 而国内的插头一般是这样的 这时候,你就需要一个转换插头了 而适配器的工作就像是一个转换插头。你不需要从新买一个电器,也不用换一个插孔,

适配器模式

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

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

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

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

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

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

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

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

情景:

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

有一个鸭子的子类

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());
    }
}

}

外观模式

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

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

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

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

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

<span style="color: #0000ff;">public <span style="color: #0000ff;">class<span style="color: #000000;"> FacadeTest {
<span style="color: #0000ff;">public <span style="color: #0000ff;">static <span style="color: #0000ff;">void<span style="color: #000000;"> main(String[] args) {
A a = <span style="color: #0000ff;">new<span style="color: #000000;"> A();
B b = <span style="color: #0000ff;">new<span style="color: #000000;"> B();
C c = <span style="color: #0000ff;">new<span style="color: #000000;"> C();
Facade facade = <span style="color: #0000ff;">new<span style="color: #000000;"> Facade(a,b,c);
facade.ABC1();
System.out.println();
facade.ABC2();
}
}

<span style="color: #0000ff;">class<span style="color: #000000;"> A {
<span style="color: #0000ff;">public <span style="color: #0000ff;">void<span style="color: #000000;"> a1() {
System.out.println("a1"<span style="color: #000000;">);
}
<span style="color: #0000ff;">public <span style="color: #0000ff;">void<span style="color: #000000;"> a2() {
System.out.println("a2"<span style="color: #000000;">);
}
}

<span style="color: #0000ff;">class<span style="color: #000000;"> B {
<span style="color: #0000ff;">public <span style="color: #0000ff;">void<span style="color: #000000;"> b1() {
System.out.println("b1"<span style="color: #000000;">);
}
<span style="color: #0000ff;">public <span style="color: #0000ff;">void<span style="color: #000000;"> b2() {
System.out.println("b2"<span style="color: #000000;">);
}
}

<span style="color: #0000ff;">class<span style="color: #000000;"> C {
<span style="color: #0000ff;">public <span style="color: #0000ff;">void<span style="color: #000000;"> c1() {
System.out.println("c1"<span style="color: #000000;">);
}
<span style="color: #0000ff;">public <span style="color: #0000ff;">void<span style="color: #000000;"> c2() {
System.out.println("c2"<span style="color: #000000;">);
}
}

<span style="color: #0000ff;">class<span style="color: #000000;"> Facade {
A a;
B b;
C c;
<span style="color: #0000ff;">public<span style="color: #000000;"> Facade(A a,B b,C c) {
<span style="color: #0000ff;">this.a =<span style="color: #000000;"> a;
<span style="color: #0000ff;">this.b =<span style="color: #000000;"> b;
<span style="color: #0000ff;">this.c =<span style="color: #000000;"> c;
}
<span style="color: #0000ff;">public <span style="color: #0000ff;">void<span style="color: #000000;"> ABC1() {
a.a1();
b.b1();
c.c1();
}
<span style="color: #0000ff;">public <span style="color: #0000ff;">void<span style="color: #000000;"> ABC2() {
a.a2();
b.b2();
c.c2();
}
}

类图:

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

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

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

举个栗子:

不使用这个原则:

=

使用这个原则:

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

综上:

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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读