结构型模式(一) 适配器模式(Adapter)
一、动机(Motivation)
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。
如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?
二、意图(Intent)
将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
例说Adapter应用
这种实际上是一种委派的调用,本来是发送请求给MyStack,但是MyStack实际上是委派给list去处理。MyStack在这里其实就是Adapter(适配对象),list即是Adaptee(被适配的对象),而IStack就是客户期望的接口。太直接了,没什么可说的。
三、结构(Structure)
适配器有两种结构
1、对象适配器(更常用)
对象适配器使用的是对象组合的方案,它的Adapter和Adaptee的关系是组合关系,即上面例子中MyStack和list是组合关系。
OO中优先使用组合模式,组合模式不适用再考虑继承。因为组合模式更加松耦合,而继承是紧耦合的,父类的任何改动都要导致子类的改动。
上面的例子就是对象适配器。
2、类适配器(不推荐使用)
下面的例子是类适配器。
Adapter继承了ArrayList,也继承了IStack接口,它既可以使用ArrayList里的方法,也可以使用IStack接口里的方法,这样就感觉有点不伦不类。这个类违反了类应该具有单一职责的原则,它既有ArrayList的职责,也有IStack的职责,因此这种类适配不是很常用,也不推荐使用。
注意:如果一个方法有可能要委托到2个或2个以上的对象,或者2个或2个以上的类需要委托,对于对象适配器,只需要增加几个内部的属性就可以实现适配。
而对于类适配器,因为C#中类只能是单一继承,它不能继承自2个或2个以上的类,所以类适配器这里便无法使用。
四、模式的组成
可以看出,在适配器模式的结构图有以下角色:
(1)、目标角色(Target):定义Client使用的与特定领域相关的接口。
(2)、客户角色(Client):与符合Target接口的对象协同。
(3)、被适配角色(Adaptee):定义一个已经存在并已经使用的接口,这个接口需要适配。
(4)、适配器角色(Adapte) :适配器模式的核心。它将对被适配Adaptee角色已有的接口转换为目标角色Target匹配的接口。对Adaptee的接口与Target接口进行适配.
五、 适配器模式的具体实现
实现一个对栈的操作,有一个IStact接口,里面有三个方法Push(进栈)、Pop(出栈)和GetTopItem(取最顶层元素),这个IStact接口将相当于上面的Target,想要实现进栈出栈的操作,如果自己去实现数据结构显得比较麻烦,在此可以将net提供的ArrayList类拿来一用,ArrayList类就是被适配的对象,相当于上面的Adaptee。在写一个适配类StactAdapter类完成功能就可以了。
/// <summary>
/// 栈的接口
/// </summary>
public interface IStack
{
void Push(object item);
void Pop();
Object GetTopItem();
}
/// <summary>
/// 对象适配器
/// </summary>
public class StactAdapter : IStack
{
ArrayList list;
/// <summary>
/// 构造函数中实例化ArrayList
/// </summary>
public StactAdapter()
{
list = new ArrayList();
}
/// <summary>
/// 进栈
/// </summary>
/// <param name="item">压入栈的元素</param>
public void Push(object item)
{
list.Add(item);
}
/// <summary>
/// 出栈
/// </summary>
public void Pop()
{
list.RemoveAt(list.Count - 1);
}
/// <summary>
/// 取最顶层的元素
/// </summary>
/// <returns></returns>
public Object GetTopItem()
{
return list[list.Count - 1];
}
}
/// <summary>
/// 客户调用
/// </summary>
public class App
{
static void Main(string[] args)
{
IStack myStack = new StactAdapter();
myStack.Push("oec2003");
myStack.Push("oec2004");
myStack.Push("oec2005");
myStack.Pop();
Console.WriteLine(myStack.GetTopItem());
}
}
六、适配器模式的实现要点:
1、Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。
2、GoF23定义了两种Adapter模式的实现结构:对象适配器和类适配器。类适配器采用“多继承”的实现方式,在C#语言中,如果被适配角色是类,Target的实现只能是接口,因为C#语言只支持接口的多继承的特性。在C#语言中类适配器也很难支持适配多个对象的情况,同时也会带来了不良的高耦合和违反类的职责单一的原则,所以一般不推荐使用。对象适配器采用“对象组合”的方式,更符合松耦合精神,对适配的对象也没限制,可以一个,也可以多个,但是,使得重定义Adaptee的行为较困难,这就需要生成Adaptee的子类并且使得Adapter引用这个子类而不是引用Adaptee本身。Adapter模式可以实现的非常灵活,不必拘泥于GoF23中定义的两种结构。例如,完全可以将Adapter模式中的“现存对象”作为新的接口方法参数,来达到适配的目的。
3、Adapter模式本身要求我们尽可能地使用“面向接口的编程”风格,这样才能在后期很方便地适配。
适配器模式用来解决现有对象与客户端期待接口不一致的问题,下面详细总结下适配器两种形式的优缺点。
1、类的适配器模式:
优点:
(1)、可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”
(2)、可以重新定义Adaptee(被适配的类)的部分行为,因为在类适配器模式中,Adapter是Adaptee的子类
(3)、仅仅引入一个对象,并不需要额外的字段来引用Adaptee实例(这个即是优点也是缺点)。
缺点:
(1)、用一个具体的Adapter类对Adaptee和Target进行匹配,当如果想要匹配一个类以及所有它的子类时,类的适配器模式就不能胜任了。因为类的适配器模式中没有引入Adaptee的实例,光调用this.SpecificRequest方法并不能去调用它对应子类的SpecificRequest方法。
(2)、采用了 “多继承”的实现方式,带来了不良的高耦合。
2、对象的适配器模式
优点:
(1)、可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”(这点是两种实现方式都具有的)
(2)、采用 “对象组合”的方式,更符合松耦合。
缺点:
(1)、使得重定义Adaptee的行为较困难,这就需要生成Adaptee的子类并且使得Adapter引用这个子类而不是引用Adaptee本身。
3、适配器模式使用的场景:
(1)、系统需要复用现有类,而该类的接口不符合系统的需求
(2)、想要建立一个可重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
(3)、对于对象适配器模式,在设计里需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。
七、.NET 中适配器模式的实现
说道适配器模式在Net中的实现就很多了,比如:System.IO里面的很多类都有适配器的影子,当我们操作文件的时候,其实里面调用了COM的接口实现。以下两点也是适配器使用的案例:
1.在.NET中复用COM对象:
COM对象不符合.NET对象的接口,使用tlbimp.exe来创建一个Runtime Callable Wrapper(RCW)以使其符合.NET对象的接口,COM Interop就好像是COM和.NET之间的一座桥梁。
2..NET数据访问类(Adapter变体):
各种数据库并没有提供DataSet接口,使用DbDataAdapter可以将任何个数据库访问/存取适配到一个DataSet对象上,DbDataAdapter在数据库和DataSet之间做了很好的适配。当然还有SqlDataAdapter类型了,针对微软SqlServer类型的数据库在和DataSet之间进行适配。
结构型模式(一) 适配器模式(Adapter)的更多相关文章
- 设计模式---结构型模式之适配器模式(Adapter Pattern)
适配器模式定义 将一个类的接口,转换成客户期望的另外一个接口.适配器让原本接口不兼容的类可以合作无间. 适配器模式主要有两种类型:对象适配器和类适配器. 在详细解释这两种类型时,解释部分重要角色.生活 ...
- Java设计模式(7)——结构型模式之适配器模式(Adapter)
一.概述 概念 其实,举个生活中的例子的话,适配器模式可以类比转接头,比如typeC和USB的转接头,把原本只能接typeC的接口,拓展为可以接普通USB:这里的转接头一方面需要查在typeC上,一方 ...
- 结构型设计模式之适配器模式(Adapter)
结构 意图 将一个类的接口转换成客户希望的另外一个接口.A d a p t e r 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适用性 你想使用一个已经存在的类,而它的接口不符合你 ...
- GoF23种设计模式之结构型模式之适配器模式
一.概述 将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 二.适用性 1.你想使用一个已经存在的类,但是它的接口不符合 ...
- Java设计模式——结构型模式
Java设计模式中共有7种结构型模式:适配器模式.装饰模式.代理模式.外观模式.桥接模式.组合模式.享元模式.其中对象的适配器模式是各种模式的起源,其关系如下面的图:1.适配器模式 适配器模式将某个类 ...
- NET设计模式 第三部分 结构型模式(7):适配器模式(Adapter Pattern)
适配器模式(Adapter Pattern) ——.NET设计模式系列之八 Terrylee,2006年2月 概述 在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但 ...
- 设计模式06: Adapter 适配器模式(结构型模式)
Adapter 适配器模式(结构型模式) 适配(转换)的概念无处不在:电源转接头.电源适配器.水管转接头... 动机(Motivation)在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象 ...
- 初探Java设计模式2:结构型模式(代理模式,适配器模式等)
行为型模式 行为型模式关注的是各个类之间的相互作用,将职责划分清楚,使得我们的代码更加地清晰. 策略模式 策略模式太常用了,所以把它放到最前面进行介绍.它比较简单,我就不废话,直接用代码说事吧. 下面 ...
- Java设计模式之结构型模式
结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 一.适配器模式: 意图: 将一个类的接口转换成客户希望的另外一个接口.Adapter 模式使得原本由于接 ...
随机推荐
- A+B for Polynomials
This time, you are supposed to find A+B where A and B are two polynomials. Input Specification: Each ...
- nginx实现tcp负载均衡
1 安装支持库 yum -y install make zlib zlib-devel gcc-c++ libtool openssl openssl-devel yum install pcre-d ...
- Redis的5中数据类型及应用场景
Redis的全称是Remote Dictionary Server,本质上是一个Key-Value类型的内存数据库,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据Flush到硬盘行 ...
- golang内建容器
- Java基础系列3:多线程超详细总结
该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 1.线程概述 几乎所 ...
- .NET Core 中三种模式依赖注入的生命周期。
注入模式 同一个请求作用域 不同的请求作用域 AddSingleton 同一个实例 同一个实例 AddScoped 同一个实例 新实例 AddTransient 新实例 新实例
- node.js开发 npm包管理工具
npm介绍 说明:npm(node package manager)是nodejs的包管理器,用于node插件管理(包括安装.卸载.管理依赖等) 使用npm安装插件:命令提示符执行npm instal ...
- 易百教程人工智能python修正-人工智能监督学习(回归)
回归是最重要的统计和机器学习工具之一. 我们认为机器学习的旅程从回归开始并不是错的. 它可以被定义为使我们能够根据数据做出决定的参数化技术,或者换言之,允许通过学习输入和输出变量之间的关系来基于数据做 ...
- dubbo源码阅读之自适应扩展
自适应扩展机制 刚开始看代码,其实并不能很好地理解dubbo的自适应扩展机制的作用,我们不妨先把代码的主要逻辑过一遍,梳理一下,在了解了代码细节之后,回过头再来思考自适应扩展的作用,dubbo为什么要 ...
- Cookie 和 Session 总结
Cookie 和 Session 区别 cookie数据存放在客户的浏览器上,session数据放在服务器上 cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑* ...