[Head First设计模式]身边的设计模式——适配器模式
系列文章
[Head First设计模式]山西面馆中的设计模式——装饰者模式
[Head First设计模式]山西面馆中的设计模式——观察者模式
[Head First设计模式]山西面馆中的设计模式——建造者模式
[Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式
[Head First设计模式]抢票中的设计模式——代理模式
[Head First设计模式]云南米线馆中的设计模式——模版方法模式
[Head First设计模式]餐馆中的设计模式——命令模式
适配器
假设我们已经有一个软件系统,原来使用了一个第三方类库A。现在有一个新的第三方类库B,其功能等各方面都更加强大。我们希望用B来替换A,以改善我们的系统。但是B的接口与A不一样。那怎么办呢?
适配器模式定义
将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
- 有时,为复用而设计的工具箱类不能够被复用的原因仅仅是因为它的接口与专业应用领域所需要的接口不匹配(名称不一样,参数不一样等等)
- 我们可以改变工具箱类使它兼容专业领域中的类的接口,但前提是必须有这个工具箱的源代码,然而 即使我们得到了这些源代码,修改工具箱也是没有什么意义的,因为不应该仅仅为了实现一个应用,工具箱就不得不采用一些与特定领域相关的接口。
- 我们可以不用上面的方法,而定义一个适配器类,由他来适配工具箱接口和专业应用的接口。我们可以用两种方法做这件事:
- 继承专业应用类的接口和工具箱类的实现。这种方法对应Adapter模式的类版本(多继承)
- 将工具箱类的实现作为适配器类的组成部分,并且使用工具箱的接口实现适配器类。这种方法对应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设计模式]身边的设计模式——适配器模式的更多相关文章
- [Head First设计模式]生活中学设计模式——迭代器模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- [Head First设计模式]生活中学设计模式——组合模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- [Head First设计模式]生活中学设计模式——外观模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- [Head First设计模式]生活中学设计模式——状态模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- 设计模式(五)适配器模式Adapter(结构型)
设计模式(五)适配器模式Adapter(结构型) 1. 概述: 接口的改变,是一个需要程序员们必须(虽然很不情愿)接受和处理的普遍问题.程序提供者们修改他们的代码;系统库被修正;各种程序语言以及相 ...
- JAVA设计模式——第 8 章 适配器模式【Adapter Pattern】(转)
好,请安静,后排聊天的同学别吵醒前排睡觉的同学了,大家要相互理解嘛.今天讲适配器模式,这个模式也很简单,你笔记本上的那个拖在外面的黑盒子就是个适配器,一般你在中国能用,在日本也能用,虽然两个国家的的电 ...
- Java设计模式(9)适配器模式(Adapter模式)
适配器模式定义:将两个不兼容的类纠合在一起使用,属于结构型模式,需要有Adaptee(被适配者)和Adaptor(适配器)两个身份. 为何使用适配器模式 我们经常碰到要将两个没有关系的类组合在一起使用 ...
- php设计模式课程---8、适配器模式是什么
php设计模式课程---8.适配器模式是什么 一.总结 一句话总结: 充电过程中,手机充电器相对于手机和插座之间就是适配器 1.编程中的适配器是怎么回事? 写一个类(适配器),将传入的数据的格式或者内 ...
- 【设计模式】Java设计模式 - 适配器模式
[设计模式]Java设计模式 - 适配器模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一 ...
随机推荐
- openstack 命令行管理 - 目录
原文http://blog.csdn.net/signmem/article/details/19513775 相关 openstack 命令行管理, 分下面部分进行介绍 openstack 命令行 ...
- centos yum update kernel
1.查看当前kernel版本 uname -r 2.查看已安装版本 rpm -q kernel 3.查看可升级kernel版本 yum list kernel 4.升级kernel版本 yum upd ...
- Java常见问题
1. eclipse permgen space 问题: debug configrations - vm arguments最后设置:-Xms256m -Xmx512m -XX:MaxNe ...
- 《InsideUE4》-8-GamePlay架构(七)GameMode和GameState
我的世界,我做主 引言 上文我们说到在Actor层次,UE用Controller来充当APawn的逻辑控制者,也有了可以接受玩家输入的PlayerController,和能自行行动的AIControl ...
- loadrnner添加C语言代码的几种方式
今天有人在群里问,想直接把自己的C语言代码让lr调用,该怎么搞. 这东西说来简单,只是对Loadrunner这工具不熟悉可能才会有这种问题吧.个人理解,一般有三种方法吧,废话不多,直接干货. 1.直接 ...
- UVALive 4431 Fruit Weights --floyd,差分约束?
题意: 给出一些关系用aX <= bY表示, 最后查询aX 和 bY的关系,是>=,==,<=,还是不能确定,还是出现了矛盾. 解法:对每一个关系其实都可以建一条X->Y的边, ...
- javascript性能优化-repaint和reflow
repaint(重绘) ,repaint发生更改时,元素的外观被改变,且在没有改变布局的情况下发生,如改变outline,visibility,background color,不会影响到dom结构渲 ...
- OrchardNoCMS模块生成工具命令简化
OrchardNoCMS模块生成工具命令行简化列表: 目前只有codegen feature和cultures三个命令. 对应的都进行了参数简化. 例如:codegen module 简化为cod ...
- ReactNative新手学习之路03真机调试
React Native新手入门03真机调试(iOS) 从设备访问开发服务器 在启用开发服务器的情况下,你可以快速的迭代修改应用,然后在设备上查看结果.这样做的前提是你的电脑和设备必须在同一个wifi ...
- HubbleDotNet 的注册码生成器
从上次更新HubbletDotNet 到现在一晃3年多了.2012年我所在的公司被澳洲电信收购,从此我就变得特别忙,没有时间继续 HubbleDotNet 的开发和维护,非常非常的抱歉. Hubble ...