系列文章

[Head First设计模式]山西面馆中的设计模式——装饰者模式

[Head First设计模式]山西面馆中的设计模式——观察者模式

[Head First设计模式]山西面馆中的设计模式——建造者模式

[Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式

[Head First设计模式]一个人的平安夜——单例模式

[Head First设计模式]抢票中的设计模式——代理模式

[Head First设计模式]面向对象的3特征5原则

[Head First设计模式]鸭子模型——策略模式

[Head First设计模式]云南米线馆中的设计模式——模版方法模式

[Head First设计模式]餐馆中的设计模式——命令模式

适配器

假设我们已经有一个软件系统,原来使用了一个第三方类库A。现在有一个新的第三方类库B,其功能等各方面都更加强大。我们希望用B来替换A,以改善我们的系统。但是B的接口与A不一样。那怎么办呢?

方案一:重建一个新系统,实现B接口
方案二:找个中间的适配器

适配器模式定义

将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

  • 有时,为复用而设计的工具箱类不能够被复用的原因仅仅是因为它的接口与专业应用领域所需要的接口不匹配(名称不一样,参数不一样等等)
  • 我们可以改变工具箱类使它兼容专业领域中的类的接口,但前提是必须有这个工具箱的源代码,然而 即使我们得到了这些源代码,修改工具箱也是没有什么意义的,因为不应该仅仅为了实现一个应用,工具箱就不得不采用一些与特定领域相关的接口。
  • 我们可以不用上面的方法,而定义一个适配器类,由他来适配工具箱接口和专业应用的接口。我们可以用两种方法做这件事:
  1. 继承专业应用类的接口和工具箱类的实现。这种方法对应Adapter模式的类版本(多继承)
  2. 将工具箱类的实现作为适配器类的组成部分,并且使用工具箱的接口实现适配器类。这种方法对应Adapter模式的对象版本。

适用性:

以下情况使用Adapter模式:

  • 你想使用一个已经存在的类,而它的接口不符合你的需求。
  • 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。

类图

适配器模式分为类适配器模式和对象适配器模式。

类适配器模式类图:

基于类的Adapter模式的一般结构:Adaptee类为Adapter的父类,Adaptee类为适配源,适配目标(接口)也是Adapter的父类,基于类的Adapter模式比较适合应用于Adapter想修改Adaptee的部分方法的情况。

对象适配器模式:

基于对象的Adapter模式的一般结构:Adaptee类对象为Adapter所依赖,适配目标(接口)是Adapter的父类。

基于对象的Adapter模式比较适合应用于Adapter想为Adaptee添加新的方法的情况。但在Adaptee类的方法与Adapter类的方法不同名而实现功能的情况下,我们一般也使用基于对象的Adapter模式。

参与者

Target:client使用的与特定领域相关的“接口”。

Client:与符合Target接口的对象协同的专业系统。

Adaptee:一个已经存在的“接口”,它具有Client要求的功能但不符合Client的接口要求。这个接口需要适配。

Adapter:对Adaptee的接口与Target接口进行适配。

协作

Client在Adapter实例上调用一些操作(请求)。接着适配器调用Adaptee的操作实现这个请求。

 效果(类适配器和对象适配器有不同的权衡)

类适配器

用一个具体的Adapter类对Adaptee和Target进行匹配。结果是当我们想要匹配一个类以及所有它的子类时,类Adapter将不能胜任工作。

使得Adapter可以重新定义Adaptee的部分行为,因为Adapter是Adaptee的一个子类。

仅仅引入一个对象,并不需要额外的指针以间接得到Adaptee。

对象适配器

允许一个Adater与多个Adaptee(即Adaptee本身以及它的所有子类(如果有子类的话)同时工作。Adapter也可以一次给所有的Adaptee添加功能。

使得重定义Adaptee的行为比较困难。这就需要生成Adaptee的子类并且使得Adapter引用这个子类而不是引用Adaptee本身。

代码

简单模拟一下,中国人说汉语,美国人说英语。

 namespace Wolfy.适配器模式
{
/// <summary>
/// 汉语语言接口
/// </summary>
public interface IChinese
{
void Speak();
}
}

IChinese

 namespace Wolfy.适配器模式
{
/// <summary>
/// 英语语言接口
/// </summary>
public interface IEnglish
{
void Speak();
}
}

IEnglish

 namespace Wolfy.适配器模式
{
public class Chinese:IChinese
{
public void Speak()
{
Console.WriteLine("你好");
}
}
}

Chinese

 namespace Wolfy.适配器模式
{
public class American:IEnglish
{
public void Speak()
{
Console.WriteLine("Hello");
}
}
}

American

我们原来有个程序使用的中国人的对象,现在想让它使用美国人对象,但是现在美国人和中国人的语言接口不同,不能直接使用。
写一个美国人的适配器,让他看起来像中国人。

对象适配器模式:

 namespace Wolfy.适配器模式
{
/// <summary>
/// 让美国人适配器类 实现汉语接口
/// </summary>
public class AmericanAdapter:IChinese
{
/// <summary>
/// 美国人适配器包装了一个美国人对象,同时实现了汉语接口。这样就可以像使用中国人对象一样使用美国人对象了。
/// </summary>
IEnglish American;
public AmericanAdapter(IEnglish American)
{
this.American = American;
}
public void Speak()
{
American.Speak();
}
}
}

测试:

  class Program
{
static void Main(string[] args)
{
Chinese me = new Chinese();
American American = new American();
//美国人适配器 让他看起来像中国人对象 这里IChinese
IChinese adapter = new AmericanAdapter(American);
Console.WriteLine("美国人说:");
American.Speak();
Console.WriteLine("中国人说:");
Test(me);
Console.WriteLine("美国人适配器说:");
//在需要中国人对象的地方使用了美国人配器对象,
//美国人适配器对象包装了一个实现英语接口的美国人对象,所以实际使用的是美国人对象。
Test(adapter);
Console.Read();
}
/// <summary>
/// 测试
/// </summary>
/// <param name="chinese">实现汉语接口的中国人对象</param>
static void Test(IChinese chinese)
{
chinese.Speak();
}
}

结果:

类适配器模式:

让上述例子变为类适配器模式,只需修改为:

 namespace Wolfy.适配器模式
{
public class Adapter:American,IChinese
{ }
}

总结

个人感觉,适配器模式,似乎在后期扩展程序的时候用。适配器模式,就像一个中间人,两个不兼容的家伙在一起,屁话没有,通过中间人,比较容易沟通。

参考:

《Head First 设计模式》

[Head First设计模式]身边的设计模式——适配器模式的更多相关文章

  1. [Head First设计模式]生活中学设计模式——迭代器模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  2. [Head First设计模式]生活中学设计模式——组合模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  3. [Head First设计模式]生活中学设计模式——外观模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  4. [Head First设计模式]生活中学设计模式——状态模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  5. 设计模式(五)适配器模式Adapter(结构型)

      设计模式(五)适配器模式Adapter(结构型) 1. 概述: 接口的改变,是一个需要程序员们必须(虽然很不情愿)接受和处理的普遍问题.程序提供者们修改他们的代码;系统库被修正;各种程序语言以及相 ...

  6. JAVA设计模式——第 8 章 适配器模式【Adapter Pattern】(转)

    好,请安静,后排聊天的同学别吵醒前排睡觉的同学了,大家要相互理解嘛.今天讲适配器模式,这个模式也很简单,你笔记本上的那个拖在外面的黑盒子就是个适配器,一般你在中国能用,在日本也能用,虽然两个国家的的电 ...

  7. Java设计模式(9)适配器模式(Adapter模式)

    适配器模式定义:将两个不兼容的类纠合在一起使用,属于结构型模式,需要有Adaptee(被适配者)和Adaptor(适配器)两个身份. 为何使用适配器模式 我们经常碰到要将两个没有关系的类组合在一起使用 ...

  8. php设计模式课程---8、适配器模式是什么

    php设计模式课程---8.适配器模式是什么 一.总结 一句话总结: 充电过程中,手机充电器相对于手机和插座之间就是适配器 1.编程中的适配器是怎么回事? 写一个类(适配器),将传入的数据的格式或者内 ...

  9. 【设计模式】Java设计模式 - 适配器模式

    [设计模式]Java设计模式 - 适配器模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一 ...

随机推荐

  1. 关于linx中man命令内容中第一行数字的含义

    我们知道linux中man这玩意特别厉害,我们要查么个命令的使用方法.如man ls 出现如下内容 关于这写数字的含义如下表格

  2. FineReport中如何进行Informix数据库连接

    报表开发工具Finereport中,对于Informix数据库,定义数据连接处进行如下配置: 数据库:Others 驱动器:com.informix.jdbc.IfxDriver URL: jdbc: ...

  3. 基于Azure构建PredictionIO和Spark的推荐引擎服务

    基于Azure构建PredictionIO和Spark的推荐引擎服务 1. 在Azure构建Ubuntu 16.04虚拟机 假设前提条件您已有 Azure 帐号,登陆 Azure https://po ...

  4. ZBrush该如何通过结合KeyShot制作逼真玉佩

    玉在中国的文明史上有着特殊的地位,古人的很多生活器具都是玉雕成的,能常戴在身上的惟有玉佩,古语有云"君子无故,玉不去身".即便到了现代,仍有很多人佩戴玉,倒不一定是因为它有多彰显地 ...

  5. 洛谷P2158 [SDOI2008]仪仗队

    题目描述 作为体育委员,C君负责这次运动会仪仗队的训练.仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图 ...

  6. java发送email

    package com.assess.util; import java.io.File; import java.util.ArrayList; import java.util.List; imp ...

  7. java集合中List与set的区别

       java集合中List与set的区别.     List可以存储元素为有序性并且元素可以相同.     set存储元素为无序性并且元素不可以相同.     下面贴几段代码感受一下: ArrayL ...

  8. 3.bootstrap练习笔记-媒体内容

    bootstrap练习笔记-多媒体对象 1.在bootstrap中,如果想存放内容,一种解决的方式就是利用media这个class 首先要设置一个div.container作为一个总的容器来存放内容 ...

  9. Java并发编程:深入剖析ThreadLocal

    原文出处: 海 子 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLocal的理解,然后根据Threa ...

  10. iTextSharp生成pdf的一个简单例子

    效果图: 参考:http://www.cnblogs.com/CareySon/archive/2011/11/09/2243496.html http://www.cnblogs.com/julyl ...