适配器的适用场景
代码的复用性强。
我们一直在使用适配器,如果 只有USB连接头,无法将手机插到标准的插座上面充电 ,这时需要的一个适配器,一端接USB连接头,另一端接插座
活动专题,例抽奖,固定的规则是充值有抽奖机会,但是突然来了一个需求说充值还要分享才能有抽奖机会,这时可以运用上这个设计模式
案例一(来自于php 设计模式 书) – 假设一个企业网站同时销售软件服务和软件产品,目前所有的交易都在美国进行,后续业务决定向欧洲发展要增加货币换算(增加适配器)
案例二是自已设计于活动专题业务上,只是将逻辑摘取出来,代码不可直接运行
优点
灵活性扩展性都很好
将目标类和适配者类解耦
适配器所涉及的角色包括下面几种:
目标(Target):定义一个客户端使用的特定接口。
客户端(Client):使用目标接口,与和目标接口一致的对象合作。
被适配者(Adaptee):一个现存需要适配的接口。
适配器(Adapter):负责将Adaptee的接口转换为Target的接口。适配器是一个具体的类,这是该模式的核心。
适配器分为类适配器和对象适配器两种,下面将详细讲述。
案例一
来自 php 设计模式 一书的适配器设计模式案例**
/**
* EuroCalc.php
* 美元 - 能累加购买的服务和产品的价格 来自于php 设计模式
*/
class DollarCalc {
private $dollar;
private $product;
private $service;
public $rate = 1;
public function requestCalc($productNow,$serviceNow) {
$this->product = $productNow;
$this->service = $serviceNow;
$this->dollar = $this->product + $this->service;
return $this->requestCount();
}
private function requestCount() {
$this->dollar *= $this->rate;
return $this->dollar;
}
}
/**
* EuroCalc.php
* 欧元 - 能累加购买的服务和产品的价格
*/
class EuroCalc {
private $euro;
private $product;
private $service;
public $rate = 1;
public function requestCalc($productNow,$serviceNow) {
$this->product = $productNow;
$this->service = $serviceNow;
$this->euro = $this->product + $this->service;
return $this->requestCount();
}
private function requestCount() {
$this->euro *= $this->rate;
return $this->euro;
}
}
/**
* 接口 ITarget.php
*/
interface ITarget {
function requester();
}
/**
* 例:找一个合适的适配器来适合欧洲的插座一样,以下就是创建这个适配器
* EuroAdapter 实现了一个接口又扩展了一个类
*/
class EuroAdapter extends EuroCalc implements ITarget {
public function __construct() {
$this->requester();
}
public function requester() {
$this->rate = 0.8111;
return $this->rate;
}
}
/**
* 用户
*/
class Client {
private $euroRequest;
private $dollarRequest;
public function __construct() {
$this->euroRequest = new EuroAdapter();
$this->dollarRequest = new DollarCalc();
$euros = "€";
echo "Euros:$euros".$this->makeAdapterRequest($this->euroRequest)."<br />";
echo "dollar:".$this->makeDollarRequest($this->dollarRequest);
}
public function makeAdapterRequest(ITarget $req) {
return $req->requestCalc(40,50);
}
public function makeDollarRequest(DollarCalc $req) {
return $req->requestCalc(40,50);
}
}
$worker = new Client();
案例二 个人运用于自动化活动专题的接口设计
抽奖例子(代码只显示对应的设计逻辑部分)
<?php
/**
* 适配器模式 - 抽奖接口
* comment 当后台规则不满足自动化,可以添加对应的适配器,增加代码的复用
* author AT
*/
namespace controller;
// 每个月份对应的适配器 06年3月 = SixMarch
use \Adapter\SixMarch\LotteryAdapter;
/**
* 抽奖接口 入口文件
*/
final class Lottery extends WebController
{
// 活动的配置信息 存放后台配置的活动信息
private $hd_info;
public function __construct() {
// 加载配置信息
$this->hd_info = '';
}
public function _lottery()
{
// 实例
$lottery = new LotteryAdapter($hd_info);
// 取得抽奖结果
$rs = $lottery->_getLotteryResult();
return $rs;
}
}
namespace controller;
use \bbts\App as BaseApp;
/**
*
*/
class LotteryAdapter extends AutoLottery implements ILottery
{
public function __construct($hd_info) {
// 后台配置是否需要使用适配器
if($hd_info['use_adapter'] === true) {
$adapter_name = $hd_info['adapter_name'];
// $adapter_name = 'adapter_name'; test
$this->$adapter_name();
}
}
/**
* adapter_name 该活动对应的适配器
*/
private function adapter_name()
{
// 假设不符合自动化的需求条件是必须进入游戏后5分才可抽奖,增加适配器的该内容即可,从而不用重写整个抽奖活动
$game_info = App::$app->model()->checkEnterGameInfo();
if(strtotime($info['TIME']) - time() < 300) {
$this->adapter_status = false;
$this->adapter_code = -51;
}
}
}
namespace controller;
use \bbts\App as BaseApp;
/**
* 自动化抽奖接口的基类
*/
class AutoLottery {
// 单独开发条件的状态
public $adapter_status = true;
public $adapter_code = 0;
public function _getLotteryResult(){
// 最后判断适配器的状态
if(!$this->adapter_status) {
App::jetJsonpOutput($this->adapter_return_code);
}
// 业务逻辑判断
// 通过则将数据入库
$rs_status = App::$app->model()->insert($rs);
// 返回结果
return $rs;
}
}
?>