接口适配器,写了一个 demo,不知道理解的对不对?
2023-08-07 原版(非适配器)
- 适配器模式:接口适配器,写了一个 demo,不知道理解的对不对,请大家指教,感谢。
<?php /** * 设计模式:接口适配器 * 作用:手机接口适配器 * * @author Tacks */ namespace App\Structural\Adapter\IphoneInterfaceAdapter; /** * 接口:电子设备(不同电压的电子设备适配为统一的接口) */ interface ElectronicDeviceInterface { public function use(); } /** * 抽象类:电子设备 * * 实现:电子设备接口 */ abstract class ElectronicDeviceAbstract implements ElectronicDeviceInterface { public function use() { } } /** * 具体的适配器:5v 普通 */ class Power5vAdapter extends ElectronicDeviceAbstract { public function use() { return 5; } } /** * 具体的适配器:10v 快充 */ class Power10vAdapter extends ElectronicDeviceAbstract { public function use() { return 10; } } /** * 具体的适配器:200v 高压,适用于大功率电器 */ class Power220vAdapter extends ElectronicDeviceAbstract { public function use() { return 220; } } /** * 业务使用:手机客户端类 */ class ClientIphone { const VOLTS = [5, 10]; const NAME = '手机'; /** * 适配器 * * @param ElectronicDeviceInterface $dest * @return void */ public function charge(ElectronicDeviceInterface $dest) { $value = $dest->use(); if (in_array($value, self::VOLTS)) { echo sprintf("[%s] %s:%s %s使用到%sV电压,准备充电", date("Y-m-d H:i:s"), __CLASS__ , __FUNCTION__, self::NAME, $value). PHP_EOL ; } else { echo sprintf("[%s] %s:%s %s应该采用%sV电压,但是实际上是%sV,无法充电", date("Y-m-d H:i:s"), __CLASS__ , __FUNCTION__, self::NAME, json_encode(self::VOLTS), $value). PHP_EOL ; } } } /** * 业务使用:空调客户端类 */ class ClientAirConditioner { const VOLT = 220; const NAME = '空调'; public function charge(ElectronicDeviceInterface $dest) { $value = $dest->use(); if ($value == self::VOLT) { echo sprintf("[%s] %s:%s %s使用到%sV电压,准备充电", date("Y-m-d H:i:s"), __CLASS__ , __FUNCTION__, self::NAME, self::VOLT). PHP_EOL ; } else { echo sprintf("[%s] %s:%s %s应该采用%sV电压,但是实际上是%sV,无法充电", date("Y-m-d H:i:s"), __CLASS__ , __FUNCTION__, self::NAME, self::VOLT, $value). PHP_EOL ; } } } // 适配器模式的主要作用是将一个类的接口转换成客户端所期望的另一个接口 // 在这个示例中,适配器类充当了接口适配器的角色,它们通过实现目标接口 ElectronicDeviceInterface,并提供了符合要求的电压值 $myIphone = new ClientIphone(); $myIphone->charge(new Power5vAdapter()); $myIphone->charge(new Power10vAdapter()); $myIphone->charge(new Power220vAdapter()); $myAir = new ClientAirConditioner(); $myAir->charge(new Power5vAdapter()); $myAir->charge(new Power220vAdapter()); - Output
[2023-08-07 10:56:39] App\Structural\Adapter\IphoneInterfaceAdapter\ClientIphone:charge 手机使用到5V电压,准备充电 [2023-08-07 10:56:39] App\Structural\Adapter\IphoneInterfaceAdapter\ClientIphone:charge 手机使用到10V电压,准备充电 [2023-08-07 10:56:39] App\Structural\Adapter\IphoneInterfaceAdapter\ClientIphone:charge 手机应该采用[5,10]V电压,但是实际上是220V,无法充电 [2023-08-07 10:56:39] App\Structural\Adapter\IphoneInterfaceAdapter\ClientAirConditioner:charge 空调应该采用220V电压,但是实际上是5V,无法充电 [2023-08-07 10:56:39] App\Structural\Adapter\IphoneInterfaceAdapter\ClientAirConditioner:charge 空调使用到220V电压,准备充电 2023-08-08 适配器理解-适配管理器
感谢评论区的大佬,思考了适配器后,再次实现代码。
/** * 设计模式:适配器模式 - 适配管理器 * * 中心思想:用于将不兼容的接口转换为客户端期望的接口 * * 目标接口:Target * LineInterface * * 不同的充电接口: * LightningLineInterface * TypecLineInterface * TypecUsbInterface * 不同的手机实现: * Apple * Huawei * Xiaomi * Realme * Nokia * 客户端: * (new Human)->phoneChange($phone, $config); 永远都是这样调用充电,传入手机设备 * * 适配器主要分为: * 适配器接口:PhoneChargeAdapterInterface * 不同适配器:LightningAdapter TypecAdapter * 适配管理器:PhoneChargeManage * 适配管理器,通过手机类型创建不同的适配器对象,再调用适配器方法完成充电 * * * @author Tacks */ - 不同手机充电线 Interface
// 充电线 interface LineInterface { const WHAT = '手机充电线'; } // Lightning 充电线接口 interface LightningLineInterface extends LineInterface { function lightning(); } // Typec 充电线接口 interface TypecLineInterface extends LineInterface { function typec(); } // Typec USB 充电线接口 interface TypecUsbInterface extends LineInterface { function usb(); } - 不同手机充电方法
// Apple 手机类,实现 LightningLineInterface class Apple implements LightningLineInterface { const MAX_POWER = '29W'; function lightning() { echo sprintf("[%s] typec %s...", __CLASS__, self::MAX_POWER). PHP_EOL ; } } // Huawei 手机类,实现 TypecLineInterface 接口 class Huawei implements TypecLineInterface { const MAX_POWER = '100W'; function typec() { echo sprintf("[%s] typec %s...", __CLASS__, self::MAX_POWER). PHP_EOL ; } } // Xiaomi 手机类,实现 TypecLineInterface 接口 class Xiaomi implements TypecLineInterface { const MAX_POWER = '120W'; function typec() { echo sprintf("[%s] typec %s...", __CLASS__, self::MAX_POWER) . PHP_EOL ; } } // Realme 手机类,实现 TypecLineInterface 接口 class Realme implements TypecLineInterface,LineInterface { const MAX_POWER = '240W'; function typec() { echo sprintf("[%s] typec %s...", __CLASS__, self::MAX_POWER). PHP_EOL ; } } // Nokia 手机类,实现 TypecUsbInterface 接口 class Nokia implements TypecUsbInterface { const MAX_POWER = '2.5W'; function usb() { echo sprintf("[%s] usb %s...", __CLASS__, self::MAX_POWER). PHP_EOL ; } } - 不同类型的手机充电适配器
- 类似把吃肉的动物和吃素的动物分开适配
- 我这里就是不同充电口的,就按照不同的手机来适配
// 手机充电适配器 interface PhoneChargeAdapterInterface { public function charge($phone); } // Lightning 适配器类,实现 PhoneChargeAdapterInterface 适配器接口 class LightningAdapter implements PhoneChargeAdapterInterface { public function charge($phone) { $phone->lightning(); } } // Typec 适配器类,实现 PhoneChargeAdapterInterface 适配器接口 class TypecAdapter implements PhoneChargeAdapterInterface { public function charge($phone) { $phone->typec(); } } - 统一适配管理器
- 用来管理多个适配器
// 适配管理器 class PhoneChargeManage { // 适配器对象 private $adapterMap = []; // 充电 public function charge($name) { $key = strtolower($name); if (in_array($key, $this->adapterMap)) { return $this->adapterMap[$name]; } return $this->createAdapter($key); } // 创建适配器对象 public function createAdapter($key) { $driverMethod = 'create' . ucfirst($key) . 'Driver'; if (!method_exists($this, $driverMethod)) { throw new \Exception("PhoneChargeManage [{$key}]'s Driver is not supported."); } $this->adapterMap[$key] = $this->$driverMethod(); return $this->adapterMap[$key]; } public function createLightningDriver() { return new LightningAdapter(); } public function createTypecDriver() { return new TypecAdapter(); } } - 客户希望永远都是统一的方式调用
// 人 class Human { // 手机充电方法 function phoneChange(LineInterface $phone, array $config) { // 创建适配器管理器 $manage = new PhoneChargeManage(); // 获取适配器类型 $driver = $this->getDriver($phone, $config); // 根据适配器类型获取适配器对象 $adapter = $manage->charge($driver); // 使用适配器对象进行手机充电 $adapter->charge($phone); } // 获取适配器类型 public function getDriver(LineInterface $phone, array $config) { foreach ($config as $keyDriver => $lineItem) { if (in_array(get_class($phone), $lineItem)) { return $keyDriver; } } return 'default'; } } - 具体调用
// 配置信息 $config = [ 'lightning' => [ Apple::class, ], 'typec' => [ Huawei::class, Xiaomi::class, ], 'usb' => [ Nokia::class, ], ]; try { $tacks = new Human(); $tacks->phoneChange(new Apple(), $config); $tacks->phoneChange(new Huawei(), $config); $tacks->phoneChange(new Nokia(), $config); } catch(\Exception $e) { echo sprintf("[Error] message:%s...", $e->getMessage()). PHP_EOL ; }

关于 LearnKu
下面我举一个例子
现在有一个农场主, 他要负责照看小鸡和小狗。如果没有适配器的话, 高层次的实现依赖于底层实现,就形成了一种耦合关系。 即农场主必须知道每一种动物是怎么吃的, 他才能喂。 比如农场主的字典里没有小猫, 小猫就喂不了。
然后我们定义一个照看动物适配器
修改一下农场主, 以前是直接喂, 现在是通过适配器喂。农场主喂的时候不关心这个动物到底怎么吃,只要查一下吃肉或者吃素就可以喂了。 即高层次实现不依赖低层次实现,实现了解耦。