• 售前

  • 售后

热门帖子
入门百科

PHP设计模式之适配器模式定义与用法详解

[复制链接]
执着294 显示全部楼层 发表于 2021-10-25 19:49:50 |阅读模式 打印 上一主题 下一主题
本文实例陈诉了PHP操持模式之适配器模式界说与用法。分享给各人供各人参考,详细如下:
适配器很容易明白, 大多数人家庭都有手机转接器, 用来为移动电话充电,这就是一种适配器. 假如只有USB讨论, 就无法将移动电话插到标准插座上. 实际上, 必须利用一个适配器, 一端接USB插头, 一端接插座. 固然, 你可以拿出电气工具,改装USB连讨论, 大概重新安装插座, 不外这样会带来很多额外的工作, 而且大概会把连讨论或插座弄坏. 所以, 最可取的方法就是找一个适配器. 软件开发也是如此.
类适配器模式(利用继续)
类适配器模式很简朴, 不外与对象适配器模式相比, 类适配器模式的机动性弱些, 类适配器简朴的原因在于 , 适配器(Adapter)会从被适配者(Adaptee)继续功能, 所以适配模式中需要编写的代码比力少.
由于类适配器模式包罗双重继续, 但是PHP并不支持双重继续, 不外荣幸的是,PHP可以用接口来模拟双重继续, 下面是一个正确的布局, 不光继续了一个类, 同时还继续了一个接口
  1. class ChildClass extends ParentClass implements ISomeAdapter
  2. {
  3. }
复制代码
实现类适配器模式时, 到场者必须包罗一个PHP接口
下面以一个钱币兑换为例来演示:
假设有一个企业网站在同时销售软件服务和软件产物, 目前, 全部生意业务都在美国举行, 所以完全可以用美元来完成全部盘算.现在开发职员盼望能有一个转换器能处理美元和欧元的兑换, 而不改变原来按美元生意业务额的类.通过增长一个适配器, 现在程序即可以用美元盘算也可以用欧元盘算.
DollarCalc.php
  1. <?php
  2. class DollarCalc
  3. {
  4. private $dollar;
  5. private $product;
  6. private $service;
  7. public $rate = 1;
  8. public function requestCalc($productNow, $serviceNow)
  9. {
  10.   $this->product = $productNow;
  11.   $this->service = $serviceNow;
  12.   $this->dollar = $this->product + $this->service;
  13.   return $this->requestTotal();
  14. }
  15. public function requestTotal()
  16. {
  17.   $this->dollar *= $this->rate;
  18.   return $this->dollar;
  19. }
  20. }
复制代码
查看这个类,可以看到此中有一个属性$rate,requestTotal()方法利用$rate盘算一次生意业务的金额.在这个版本中, 这个值设置为1,实际上总金额无需再乖以兑换率, 不外假如要为客户提供扣头大概要增长额外服务或产物的附加费, $rate变量会很方便. 这个类并不是得当器模式的一部分, 不外这是一个起点.
需求变革了
现在客户的公司要向欧洲发展,所以需要开发一个应用, 可以大概用欧元完成同样的盘算. 你盼望这个欧元盘算可以大概像DollarCalc一样, 所要做的就是改变变量名.
EuroCalc.php
  1. <?php
  2. class EuroCalc
  3. {
  4. private $euro;
  5. private $product;
  6. private $service;
  7. public $rate = 1;
  8. public function requestCalc($productNow, $serviceNow)
  9. {
  10.   $this->product = $productNow;
  11.   $this->service = $serviceNow;
  12.   $this->euro = $this->product + $this->service;
  13.   return $this->requestTotal();
  14. }
  15. public function requestTotal()
  16. {
  17.   $this->euro *= $this->rate;
  18.   return $this->euro;
  19. }
  20. }
复制代码
接下来, 再把应用的别的部分插入到EuroCalc类中. 不外,因为客户的全部数据都是按美元盘算的.换句话说, 假如不重新开发整个程序, 就无法在系统中"插入"这个欧元盘算. 但是你不想这么做. 为了到场EuroCalc, 你需要一个适配器: 就像找一个适配器来顺应欧洲的插座一样, 可以创建一个适配器, 使你的系统可以大概利用欧元. 荣幸的是, 类适配器正是为这样的情况操持的.起首需要创建一个接口. 在这个类图中, 这个接口名为ITarget. 它只有一个方法
  1. requester()
复制代码
. requester()是一个抽象方法, 要由接口的详细实现来实现这个方法.
ITarget.php
  1. <?php
  2. interface ITarget
  3. {
  4. public function requester();
  5. }
复制代码
现在开发职员可以实现
  1. requester()
复制代码
方法, 哀求欧元而不是美元.
在利用继续的适配器操持模式中, 适配器(Adapter)到场都既实现ITarget接口,还实现了详细类EuroCalc. 创建EuroAdapter不需要做太多工作, 因为大部分工作已经在EuroCal类中完成.现在要做的就是实现
  1. request()
复制代码
方法, 使它能把美元值转换为欧元值.
EuroAdapter.php
  1. <?php
  2. include_once('EuroCalc.php');
  3. include_once('ITarget.php');
  4. class EuroAdapter extends EuroCalc implements ITarget
  5. {
  6. public function __construct()
  7. {
  8.   $this->requester();
  9. }
  10. public function requester()
  11. {
  12.   $this->rate = 0.8111;
  13.   return $this->rate;
  14. }
  15. }
复制代码
类适配模式中, 一个详细类会继续另一个详细类, 有这种布局的操持模式很少见, 大多数操持模式中, 险些都是继续一个抽象类, 并由类根据需要实现其抽象方法和属性. 换句话说, 一般谈到继续时, 都是详细类继续抽象类.
由于既实现了一个接口又扩展了一个类, 所以EuroAdapter类同时拥有该接口和详细类的接口. 通过利用requester()方法, EuroAdapter类可以设置rate值(兑换率), 从而能利用被适配者的功能, 而元而做任何改变.
下面界说一个Client类, 从EuroAdapter和DollarCalc类发出哀求. 可以看到,原来的DollarCalc仍能很好地工作, 不外它没有ITarget接口.
Client.php
  1. <?php
  2. include_once('EuroAdapter.php');
  3. include_once('DollarCalc.php');
  4. class Client
  5. {
  6. public function __construct()
  7. {
  8.   $euro = '';
  9.   echo "区元: $euro" . $this->makeApapterRequest(new EuroAdapter()) . '<br />';
  10.   echo "美元: $: " . $this->makeDollarRequest(new DollarCalc()) . '<br />';
  11. }
  12. private function makeApapterRequest(ITarget $req)
  13. {
  14.   return $req->requestCalc(40,50);
  15. }
  16. private function makeDollarRequest(DollarCalc $req)
  17. {
  18.   return $req->requestCalc(40,50);
  19. }
  20. }
  21. $woker = new Client();
复制代码
运行结果如下:
  1. Euros: 72.999
  2. Dollars: $: 90
复制代码
可以看到,美元和欧元都可以处理, 这就是适配器模式的方便之处.
这个盘算很简朴, 假如是针对更为复杂的盘算, 继续要提供建立类适配器的Target接口的须要接口和详细实现
利用组合的适配器模式
对象适配器模式利用组合而不是继续, 不外它也会完成同样的目标. 通过比力这两个版本的适配器模式, 可以看出它们各自的优缺点. 接纳类适配器模式时,适配器可以继续它需要的大多数功能, 只是通过接口轻微调. 在对象适配器模式中 适配器(Adapter)到场利用被适配者(Adaptee), 并实现Target接口. 在类适配器模式中, 适配器(Adapter)则是一个被适配者(Adaptee), 并实现Target接口.
示例: 从桌面环境转向移动环境
PHP程序员经常会遇到这样一个题目:需要顺应移动环境而做出调解.不久之前,你大概只需要考虑提供一个网站来顺应多种不同的桌面环境. 大多数桌面都利用一个布局, 再由操持职员让它更雅观. 对于移动装备, 操持职员和开发职员不光需要重新考虑桌面和移动环境中页面表现的操持元素, 还要考虑怎样从一个环境切换到另一个环境.
起首来看桌面端的类Desktop(它将需要一个适配器). 这个类利用了一个简朴但很宽松的接口:
IFormat.php
  1. <?php
  2. interface IFormat
  3. {
  4. public function formatCSS();
  5. public function formatGraphics();
  6. public function horizontalLayout();
  7. }
复制代码
它支持css和图片选择, 不外此中一个方法指示一种水平布局, 我们知道这种布局并不实用小的移动装备.下面给出实现这个接口的Desktop类
Desktop.php
  1. <?php
  2. include_once('IFormat.php');
  3. class Desktop implements IFormat
  4. {
  5. public function formatCSS()
  6. {
  7.   echo "引用desktop.css<br />";
  8. }
  9. public function formatGraphics()
  10. {
  11.   echo "引用desktop.png图片<br />";
  12. }
  13. public function horizontalLayout()
  14. {
  15.   echo '桌面:水平布局';
  16. }
  17. }
复制代码
题目来了, 这个布局对于小的移动装备来说太宽了. 所以我们的目标是仍接纳同样的内容, 但调解为一种移动操持.
下面来看移动端的类Mobile
起首移动端有一个移动端的接口
IMobileFormat
  1. <?php
  2. interface IMobileFormat
  3. {
  4. public function formatCSS();
  5. public function formatGraphics();
  6. public function verticalLayout();
  7. }
复制代码
可以看到, IMobileFormat接口和IFormat接口是不一样的,也就是不兼容的, 一个包罗了方法horizontalLayout(), 另一个包罗方法verticalLaout(), 它们的差别很小, 最告急的区别是: 桌面操持可以接纳水平的多栏布局, 而移动操持要利用垂直布局,而适配器就是要办理这个题目
下面给出一个实现了IMoibleFormat接口的Mobile类
Mobile.php
  1. <?php
  2. include_once('IMobileFormat.php');
  3. class Mobile implements IMobileFormat
  4. {
  5. public function formatCSS()
  6. {
  7.   echo "引用mobile.css<br />";
  8. }
  9. public function formatGraphics()
  10. {
  11.   echo "引用mobile.png图片<br />";
  12. }
  13. public function verticalLayout()
  14. {
  15.   echo '移动端:垂直布局';
  16. }
  17. }
复制代码
Mobile类和Desktop类非常相似, 不外是图片和CSS引用不同
接下来,我们需要一个适配器,将Desktop和Mobile类结合在一起
MobileAdapter.php
  1. <?php
  2. include_once('IFormat.php');
  3. include_once('Mobile.php');
  4. class MobileAdapter implements IFormat
  5. {
  6. private $mobile;
  7. public function __construct(IMobileFormat $mobileNow)
  8. {
  9.   $this->mobile = $mobileNow;
  10. }
  11. public function formatCSS()
  12. {
  13.   $this->mobile->formatCSS();
  14. }
  15. public function formatGraphics()
  16. {
  17.   $this->mobile->formatGraphics();
  18. }
  19. public function horizontalLayout()
  20. {
  21.   $this->mobile->verticalLayout();
  22. }
  23. }
复制代码
可以看到,MobileAdapter实例化时要提供一个Mobile对象实例.还要注意 ,范例提示中利用了IMobileFormat, 确保参数是一个Mobile对象.有意思的是, Adapter到场者通过实现horizontalLayout()方法来包罗
  1. verticalLayout()
复制代码
方法.实际上, 全部MobileAdapter方法都包装了一个Mobile方法.可巧的是, 适配器到场者中的一个方法并不在适配器接口中(
  1. verticalLayout()
复制代码
);它们大概完全不同, 适配器只是把它们包装在适配器接口(IFormat)的某一方法中.
客户调用(Client)
Client.php
  1. <?php
  2. include_once('Mobile.php');
  3. include_once('MobileAdapter.php');
  4. class Client
  5. {
  6. private $mobile;
  7. private $mobileAdapter;
  8. public function __construct()
  9. {
  10.   $this->mobile = new Mobile();
  11.   $this->mobileAdapter = new MobileAdapter($this->mobile);
  12.   $this->mobileAdapter->formatCSS();
  13.   $this->mobileAdapter->formatGraphics();
  14.   $this->mobileAdapter->horizontalLayout();
  15. }
  16. }
  17. $worker = new Client();
复制代码
适配器模式中的Client类必须包装Adaptee(Mobile)的一个实例, 以便集成到Adapter本身.实例化Adapter时, Client利用Adatee作为参数来完成Adapter的实例化.所以客户必须起首创建一个Adapter对象(
  1. new Mobile()
复制代码
), 然后创建一个
  1. Adapter((new MobileAdapter($this->mobile))
复制代码
.
Client类的大多数哀求都是通过MobileAdapter发出的. 不外这个代码的最后他利用了Mobile类的实例.
适配器和变革
PHP程序员要即该面临变革.不同版本的PHP会变革, 大概增长新的功能, 别的还大概取消一些功能.而且随着PHP的大大小小的变革,MySQL也在改变.例如, mysql的扩展包升级为mysqli, PHP开发职员需要相应调解, 要改为利用mysqli中的新API.这里得当接纳适配器模式吗?大概不得当.适配器大概实用, 大概不实用,这取决于你的程序怎样设置.固然可以重写全部连接和交互代码, 不外这可不是适配器模式的本意, 这就像是重新安装USB连讨论, 想把它插进标准的墙上插座一样. 不外, 假如全部原来的mysql代码都在模块中, 你可以修改这个模块(类),换入一个有相同接口的新模块.只是要利用mysqli而不是mysql.我不以为互换等同于适配器, 不外原理是一样的, 在适配器模式中, 原来的代码没有任何改变, 有变革的只是适配器.
假如需要结合利用两个不兼容的接口, 这种情况下, 适配器模式最实用.适配器可以完成接口的"攀亲".可以把适配器看作是一个婚姻顾问;通过创建一个公共接口来降服双方的差别.利用 这种操持模式, 可以促成二者的互助,而制止完全重写某一部分.
更多关于PHP相干内容感爱好的读者可查看本站专题:《php面向对象程序操持入门教程》、《PHP基本语法入门教程》、《PHP数组(Array)操纵技巧大全》、《php字符串(string)用法总结》、《php+mysql数据库操纵入门教程》及《php常见数据库操纵技巧汇总》
盼望本文所述对各人PHP程序操持有所资助。

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作