之前买过个ipad玩,当用其充电器充电时遇到了点麻烦(有的同学应该知道),家里没有适合它的插座。还好,卖家送了个接头转换部件,问题轻松解决。这就是适配器的作用。
<?php interface IUserInfo{ public function getUserName(); public function getUserId(); public function getUserInfo(); } class UserInfo implements IUserInfo{ public function getUserId() { return 123; } public function getUserName() { return 'XXXX'; } public function getUserInfo() { return array( 'userId' => 123, 'userName' => 'XXXX' ); } } interface IOuterUser{ public function getOutUserId(); public function getOutUserName(); public function getOutUserInfo(); } class OutUser implements IOuterUser{ public function getOutUserId() { return array( 'id' => 111 ); } public function getOutUserName() { return array( 'name' => 'OOOO' ); } public function getOutUserInfo() { return array( 'id' => 111, 'name' => 'OOOO' ); } } ?>
看下这段代码,有两个获取用户信息的接口,一个内部,一个外部,可以发现,两个接口的实现类的返回类型有完全不同。好比,现在内部的接口就是“插座”,外部的接口就是ipad,现在需要一个“适配器”将这个外部的接口给转化成内部的。类图如下:
OutUserInfo就是我的适配器,代码如下:
class OutUserInfo extends OutUser implements IUserInfo{ public function getUserId() { $return = $this->getOutUserId(); return $return['id']; } public function getUserName() { $return = $this->getOutUserName(); return $return['name']; } public function getUserInfo() { $userInfo = $this->getOutUserInfo(); return array( 'userId' => $userInfo['id'], 'userName' => $userInfo['name'] ); } } $outUserInfo = new OutUserInfo(); var_dump( $outUserInfo->getUserId() ); var_dump( $outUserInfo->getUserName() ); var_dump( $outUserInfo->getUserInfo() ); 运行结果: int(111) string(4) "OOOO" array(2) { ["userId"]=> int(111) ["userName"]=> string(4) "OOOO" } [Finished in 0.3s]
有人会问,为什么不让内部的转化成外部的?相像一下,你家里现在所有的插座都是只能插两角的(ipad是三角的),现在全部转化成三角,那手机等等其他用两角的怎么充电?
适配器模式的定义
将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。适配器模式由三个角色构成:
1、Target目标角色
该角色定义把其他类转换为何种接口,也就是我们的期望接口,例子中的IUserInfo接口中就是目标角色。
2、Adaptee源角色
就是被转换的角色。例子中的OutUser
3、Adapter适配器角色
适配器的核心角色,其他的两个角色都是已经存在的角色,而适配器角色是需要新建立的,它的职责非常简单,把源角色转换为目标角色。
适配器模式的优点
1、适配器模式可以让两个没有任何关系的类在一起运行,只要适配器这个角色能够搞定他们就成。
2、增加了类的透明性
想想看,我们访问的Target目标角色,但是具体的实现都委托给了源角色,而这些对高层次模块是透明的,也是它不需要关心的。
3、提高了类的复用度
4、灵活性非常好
某天,我的ipad坏了,扔了,因此适配器拔掉就可以了。太方便了
适配器模式的使用场景
适配器模式的应用场景只要记住一点就足够了:你有动机修改一个已经上线的接口时,适配器模式可能是最适合你的模式。
适配器模式的注意事项
适配器模式最好在详细设计阶段不要考虑它,它不是为了解决还处在开发阶段的问题,而是解决正在服役的项目问题,没有一个系统分析师会在做详细设计的时候考虑使用适配器模式,这个模式使用的主要场景是扩展应用中。项目一定要遵守依赖倒置原则和里氏替换原则,否则即使在适合使用适配器的场合下,也会带来非常大的改造。
适配器模式的扩展
上面的例子是比较幸运的情况,试想一下,如果外部不是一个接口,而是多个,该如何?
<?php interface IUserInfo{ public function getUserName(); public function getUserId(); } class UserInfo implements IUserInfo{ public function getUserId() { return 123; } public function getUserName() { return 'XXXX'; } } interface IOuterUserId{ public function getOutUserId(); } interface IOuterUserName{ public function getOutUserName(); } class OutUserId implements IOuterUserId{ public function getOutUserId() { return array( 'id' => 111 ); } } class OutUserName implements IOuterUserName{ public function getOutUserName() { return array( 'name' => 'OOOO' ); } } ?>
代码所示,现外部是由两个接口组成,我们知道无论是java还是php都是不支持多继承的!既然这样,那就用类关联吧。
适配器代码:
class OutUserInfo implements IUserInfo{ private $outUserid = null; private $outUserName = null; public function __construct($outUserid,$outUserName){ $this->outUserid = $outUserid; $this->outUserName = $outUserName; } public function getUserId() { $return = $this->outUserid->getOutUserId(); return $return['id']; } public function getUserName() { $return = $this->outUserName->getOutUserName(); return $return['name']; } } $outUserid = new OutUserId(); $outUserName = new OutUserName(); $outUserInfo = new OutUserInfo($outUserid,$outUserName); var_dump( $outUserInfo->getUserId() ); var_dump( $outUserInfo->getUserName() ); 运行结果: int(111) string(4) "OOOO" [Finished in 0.1s]
这种适配器叫做对象适配器,而上面的例子则是类适配器。
类适配器是类间继承,对象适配器是对象的合成关系,也可以说是类的关联关系。
适配器模式是一个补偿模式,通常用来解决接口不相容的问题,在百分之百的完美设计中是不可能使用到的,但真的有百分之百的完美设计吗?因此我们需要这么这种补偿方式来处理这完美中的不足!
相关推荐
【Windows 7 美中不足的地方】 Windows 7,微软的一款备受赞誉的操作系统,虽然在许多方面取得了显著的进步,但依然存在一些不足之处。以下是Windows 7的主要缺陷: 1. **缺少经典Windows组件** Windows 7为了...
《jQuery之美中不足小结》 jQuery作为一款广泛使用的JavaScript库,因其简洁的API和强大的DOM操作能力,深受开发者喜爱,极大地推动了Web开发的进步。然而,任何事物都有其两面性,jQuery也不例外。本文将探讨...
这种基于工作流的分组模式,大大提高了网络规划和重组的管理功能。在同一个VLAN中的工作站,不论它们实际与哪个交换机连接,它们之间的通讯就好象在独立的交换机上一样。同一个VLAN中的广播只有VLAN中的成员才能听到...
美中不足是需要 AIR 平台,这对做设计的人来说不算事儿,否则的话。。。就显得不那么随心了。 Dorado 是一款用起来比 MarkMan 更方面更灵活的标注工具。 Dorado 就更方便一些了,只有一个文件,运行起来就可以用了...
Mybatis 的基础使用方式,其中有一部分美中不足的是 Mybatis 本身并未提供分页功能,还需要我们自己手动添加 PageHelper 插件或者自己实现分页的工具类,并且对单表的操作并不友好,简单的 insert 、 update 、 ...
这个贪吃蛇项目实现了简单的GUI界面和键盘监听用户交互,美中不足是比较简陋,而且不是完全的面向对象项目。由于经验与理解尚不足,我暂时没有能力将它更加完善。如果您有好的意见,欢迎与我联系。 代码包中包含所...
可调整为无边框,如下(新版8.0比起旧版有个美中不足的地方,就是在无边框的情况下不能自由缩放窗口,必须退出无边框才行) 可以更换软件和图标皮肤(20来款),我这边加载奇慢,下载这些倒都是没问题的,有加速器...
都很漂亮,美中不足的就是兼容性较差 今天给大家推荐的这款可以兼容IE 7以及以上版本,非常适合企业类的网站使用 使用方法: 1、将head中的样式引入到你的网页中 2、将body里的代码部分拷贝到你...
推荐一款在Android平台上的蓝牙串口调试助手,完全纯净无广告,想要的调试功能都有,唯一美中不足的就是不支持设置字符编码、发送新行,但这完全无大碍,比应用市场里下载的一大片广告好多了。 资源来源于我之前看的...
美中不足的是生成后的jar文件不能正常读写文件。 如果觉得下载该资源花费积分过高,可以去(免积分)下载asqare_llk_5_jar文件,那个文件是该游戏的jar文件,下载运行看看该资源值不值10积分。 如果下载此文件,记得给...
box view,很不错,文件不大,但功能很全,但美中不足有时打开文件会出现黑条…… PdgThumbViewer,这个不错,够小,够简单。但就是没有放大缩小的功能,好在能全屏,凑合用好了! --TTT BLOG
但是美中不足就是体积太大,前不久做项目的时候遇到这个问题,恰好发现里面一个压缩过的 Ext.js只有200K,但是已经能够构建一个完整的ExtTree,于是就花了点时间把它改造成一个xml To ExtTree的这样一个小控件,分享...
然而,美中不足的是,Qt 的贝塞尔曲线只支持二次和三次,对于更高阶的似乎就无能为力了。 即便多个 quadTo() 或 cubicTo() 连用的效果也非常不理想。 因此,我想到利用贝塞尔的公式生成曲线点,然后用直线来连接,...
SourceGrid 是一个免费的完全以 C# 托管代码编写的 .NET Windows 窗体网格控件. SourceGrid 可用于显示或改变表格形式的数据。 SourceGrid 可用于绑定到一个数据源(以 ...美中不足的是SourceGrid 仅有少量的设计时支持
支持平方、立方、N次方、二次开方、三次开方、N次开方、阶乘、加减、乘、除等单独或混合计算,同时还支持对复杂的数学方程师进行计算,系统并且会列出详细的计算步骤,美中不足的是这款功能强大的计算工具目前只支持...
美中不足教程文档替换广告位没有写,广告位类型不明确,需要自己去摸索。壁纸下载功能多少有点问题,我测试朋友搭建的也没有什么问题….可能我搭建的有问题。 此套源码还是很火的,基本都是卖200以上。
可以正常显示所有列表中的好友,有声音...。。反正一般手机QQ所具备的功能都有了吧呵呵 电脑端也显示为手机QQ登陆,并且可以正常使用视频,传送文件等功能,感觉美中不足就是UI,WINCE风格,按键稍小,但不影响使用!
treeview控件TreeView详解(转载)好文章大家一起分享!...TreeView 6.0:每个层节点的最后一个节点下方还是有一部分白色的,美中不足。 假设 TreeView 控件的 Name 值为 OleTreeView6,然后在表单的 Init 事件加代码: