面向对象设计模式纵横谈:Adapter 适配器模式(笔记记录)
适配(转换)的概念无处不在
适配,即在不改变原有实现的基础上,将原先不兼容的接口转换为兼容的接口。生活中适配转换的例子太多了,也是设计模式里面比较容易理解的一个模式。
动机(Motivation)
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。
如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?
意图(Intent)
将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
——《设计模式》GoF
例说Adapter应用
这种实际上是一种委派的调用,本来是发送请求给MyStack,但是MyStack实际上是委派给list去处理。MyStack在这里其实就是Adapter(适配对象),list即是Adaptee(被适配的对象),而IStack就是客户期望的接口。太直接了,没什么可说的。
结构(Structure)
适配器有两种结构
-对象适配器(更常用)
对象适配器使用的是对象组合的方案,它的Adapter和Adaptee的关系是组合关系,即上面例子中MyStack和list是组合关系。
OO中优先使用组合模式,组合模式不适用再考虑继承。因为组合模式更加松耦合,而继承是紧耦合的,父类的任何改动都要导致子类的改动。
上面的例子就是对象适配器。
-类适配器
下面的例子是类适配器。
Adapter继承了ArrayList,也继承了IStack接口,它既可以使用ArrayList里的方法,也可以使用IStack接口里的方法,这样就感觉有点不伦不类。这个类违反了类应该具有单一职责的原则,它既有ArrayList的职责,也有IStack的职责,因此这种类适配不是很常用,也不推荐使用。
另外,如果一个方法有可能要委托到2个或2个以上的对象,或者2个或2个以上的类需要委托,对于对象适配器,只需要增加几个内部的属性就可以实现适配。
而对于类适配器,因为C#中类只能是单一继承,它不能继承自2个或2个以上的类,所以类适配器这里便无法使用。
Adapter模式的几个要点
Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。
GoF23定义了两种Adapter模式的实现结构:对象适配器和类适配器。但类适配器采用“多继承”的实现方式,带来了不良的高耦合,所以一般不推荐使用。对象适配器采用“对象组合”的方式,更符合松耦合精神。
Adapter模式可以实现的非常灵活,不必拘泥于GoF23中定义的两种结构。例如,完全可以将Adapter模式中的“现存对象”作为新的接口方法参数,来达到适配的目的。
Adapter模式本身要求我们尽可能地使用“面向接口的编程”风格,这样才能在后期很方便地适配。
.NET框架中的Adapter应用
1.在.NET中复用COM对象:
-COM对象不符合.NET对象的接口
-使用tlbimp.exe来创建一个Runtime Callable Wrapper(RCW)以使其符合.NET对象的接口
2..NET数据访问类(Adapter变体):
-各种数据库并没有提供DataSet接口
-使用DbDataAdapter可以将任何个数据库访问/存取适配到一个DataSet对象上
微软把适配器和被适配的对象分离了,它把EmployeeDAO作为适配器了。这和上面的模式有点不同,但是原理都是一样的,如果是写成下面的样子,就比较好理解了。
DataSet就是一个适配器
3.集合类中对现有对象的排序(Adapter变体):
-现有对象未实现IComparer接口
-实现一个排序适配器(继承IComparer接口),然后在其Compare方法中对两个对象进行比较
这样写是会报错的,因为要使用Array.Sort的静态方法,传入的参数类型Employee必须要求实现IComparer接口。但如果Employee类已经在很多地方使用了,我们不能更改它,这个时候可以考虑适配。
Array.Sort方法本身提供了一种重载,可以传入一个比较方法。
因此我们可以重新写一个类实现IComparer接口,这里是让员工根据年龄排序
这里的实现适配没有把适配器放在类里面。
没必要非要做成教科书上的结构才叫适配器,把适配对象直接作为参数传递一样是一种很好的做法。
面向对象设计模式纵横谈:Adapter 适配器模式(笔记记录)的更多相关文章
- 面向对象设计模式纵横谈:Singelton单件模式(笔记记录)
李建忠老师讲的<面向对象设计模式纵横谈>,早就看过了,现在有了时间重新整理一下,以前的博客[赛迪网]没有了,现在搬到博客园,重新过一遍,也便于以后浏览. 设计模式从不同的角度分类会得 ...
- C#面向对象设计模式纵横谈——1.面向对象设计模式与原则
一:设计模式简介 每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心. ---- Christopher Alexander 软件设计领域设计模式: 设计模式描述了软件设计过 ...
- 面向对象设计模式纵横谈:Bridge 桥接模式(笔记记录)
桥接模式是一个比较难理解的设计模式,设计和分析的时候也不容易把握,咱们听听“李建忠”老师是怎么来讲的.我们还是从演变的角度来说问题,一步一步的来把问题说清楚.先谈谈“抽象”和“实现”的关系. 抽象与实 ...
- 面向对象设计模式纵横谈:Abstract Factory 抽象工厂模式(笔记记录)
今天是设计模式的第二讲,抽象工厂的设计模式,我们还是延续老办法,一步一步的.演变的来讲,先来看看一个对象创建的问题. 1.如何创建一个对象 常规的对象创建方法: 这样的创建对象没有任何问题, ...
- 面向对象设计模式纵横谈:Factory Method 工厂方法模式(笔记记录)
从耦合关系谈起 耦合关系直接决定着软件面对变化时的行为 -模块与模块之间的紧耦合使得软件面对变化时,相关模块都要随之更改 -模块与模块之间的松耦合使得软件面对变化时,一些模块更容易被替换或者更改,但其 ...
- 面向对象设计模式纵横谈:Prototype 原型模式(笔记记录)
有一段时间没写东西了,今天继续把没写完的设计模式写完,今天这堂课是创建型设计模式的最后一堂课,原型设计模式,它同样也是解决了对象在创建的过程中的解耦合的情况,面对变化使代码更稳定,更准确的说是使 ...
- 面向对象设计模式纵横谈:Builder 生成器模式(笔记记录)
Builder模式的缘起 假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分要富于变化. 如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正…… 动 ...
- 设计模式(6)--Adapter(适配器模式)--结构型
1.模式定义: 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 2.模式特点: Adapter模式使原本因接口不匹配(或者不兼 ...
- C#面向对象设计模式纵横谈——6.Prototype 原型模式(创建型模式)
动机(Motivation) 在软件系统中,经常面临着“某些结构复杂的对象”的创建工作.由于需求的变化,这些对象经常面临着剧烈的变化,但他们却拥有比较稳定一致的接口. 如何应对这种变化?如何向“客户程 ...
随机推荐
- Spark Streaming 例子
NetworkWordCount.scala /* * Licensed to the Apache Software Foundation (ASF) under one or more * con ...
- mysql 更新(二)安装和基本管理
03-MySql安装和基本管理 本节掌握内容: MySQL的介绍安装.启动 MySQL破解密码 MySQL中统一字符编码 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目 ...
- lb集群lvs的3种模式
Cluster原理 集群的总类: 1.负载均衡集群(LB:Load Banlancing):实现将一个访问量或者任务量特别大的应用,给他 平均分配到不同的服务器上面,以提供高容量.大并发. 2.高可用 ...
- select(下拉标签和textarea(文本框)
Title 北京 南京 天津 武汉 石家庄 太原 dsadasd <!DOCTYPE html> <html lang="en"> <head&g ...
- UI5-文档-4.2-Bootstrap
在使用SAPUI5做一些事情之前,我们需要加载并初始化它.加载和初始化SAPUI5的过程称为引导.一旦引导完成,我们只需显示一个警告. Preview An alert "UI5 is re ...
- js实现UTC时间转为北京时间,时间戳转为时间
用了阿里云的接口,发现其穿的日期是UTC格式的.需要转换. var utc_datetime = "2017-03-31T08:02:06Z"; function utc2beij ...
- ubuntu16.04设置电池充电阈值
thinkpad在安装ubuntu16.04之后,设置充电阈值: 方法一: 使用双系统,在windows下使用联想的Lenovo setting center设置之后,在ubuntu之下也可以保持相同 ...
- Jquery detect page refresh
first thing there are 3 functions we will use: function setCookie(c_name, value, exdays) { ...
- 协变(covariance),逆变(contravariance)与不变(invariance)
协变,逆变与不变 能在使用父类型的场景中改用子类型的被称为协变. 能在使用子类型的场景中改用父类型的被称为逆变. 不能做到以上两点的被称为不变. 以上的场景通常包括数组,继承和泛型. 协变逆变与泛型( ...
- git基本命令之删除撤销操作
1.将删除文件恢复--撤销所删除的文件git checkout 文件名 2.git resetgit reset --hard commitID(或某个节点)----强制切换到某个点,会导致所修改的内 ...