PHP面向对象程序设计组合模式与装饰模式详解


Posted in PHP onDecember 02, 2016

本文实例讲述了PHP面向对象程序设计组合模式与装饰模式。分享给大家供大家参考,具体如下:

组合模式

定义:组合模式定义了一个单根继承体系,使具有截然不同职责的集合可以并肩工作。

一个军队的案例,

<?php
abstract class Unit { // 个体
  abstract function bombardStrength();
}
class Archer extends Unit { // 弓箭手
  function bombardStrength() {
    return 4;
  }
}
class LaserCannonUnit extends Unit { // 火炮手
  function bombardStrength() {
    return 44;
  }
}
?>

军队整合成员,输出火力

<?php
abstract class Unit {
  abstract function bombardStrength();
}
class Archer extends Unit {
  function bombardStrength() {
    return 4;
  }
}
class LaserCannonUnit extends Unit {
  function bombardStrength() {
    return 44;
  }
}
class Army { // 军队
  private $units = array(); // 定义私有属性 个体集
  function addUnit( Unit $unit ) { // 添加成员
    array_push( $this->units, $unit );
  }
  function bombardStrength() { // 火力
    $ret = 0;
    foreach( $this->units as $unit ) {
      $ret += $unit->bombardStrength();
    }
    return $ret;
  }
}
$unit1 = new Archer();
$unit2 = new LaserCannonUnit();
$army = new Army();
$army->addUnit( $unit1 );
$army->addUnit( $unit2 );
print $army->bombardStrength(); // 输出火力
?>

output:
48
军队进一步整合其他军队

<?php
abstract class Unit {
  abstract function bombardStrength();
}
class Archer extends Unit {
  function bombardStrength() {
    return 4;
  }
}
class LaserCannonUnit extends Unit {
  function bombardStrength() {
    return 44;
  }
}
class Army {
  private $units = array();
  private $armies= array();
  function addUnit( Unit $unit ) {
    array_push( $this->units, $unit );
  }
  function addArmy( Army $army ) {
    array_push( $this->armies, $army );
  }
  function bombardStrength() {
    $ret = 0;
    foreach( $this->units as $unit ) {
      $ret += $unit->bombardStrength();
    }
    foreach( $this->armies as $army ) {
      $ret += $army->bombardStrength();
    }
    return $ret;
  }
}
$unit1 = new Archer();
$unit2 = new LaserCannonUnit();
$army = new Army();
$army->addUnit( $unit1 );
$army->addUnit( $unit2 );
print $army->bombardStrength();
print "\n";
$army2 = clone $army; // 克隆军队
$army->addArmy( $army2 );
print $army->bombardStrength();
print "\n";
?>

output:
48
96

更好的方式,支持新增,移除等等其他功能。

<?php
abstract class Unit {
  abstract function addUnit( Unit $unit );
  abstract function removeUnit( Unit $unit );
  abstract function bombardStrength();
}
class Army extends Unit { // 军队
  private $units = array();
  function addUnit( Unit $unit ) {
    if ( in_array( $unit, $this->units, true ) ) { // $this用于调用正常的属性或方法,self调用静态的方法,属性或者常量
      return;
    }
    $this->units[] = $unit;
  }
  function removeUnit( Unit $unit ) {
    // >= php 5.3
    $this->units = array_udiff( $this->units, array( $unit ),
            function( $a, $b ) { return ($a === $b)?0:1; } );
    // < php 5.3
    // $this->units = array_udiff( $this->units, array( $unit ),
    //        create_function( '$a,$b', 'return ($a === $b)?0:1;' ) );
    // 对象数组,create_function,创建函数
  }
  function bombardStrength() {
    $ret = 0;
    foreach( $this->units as $unit ) {
      $ret += $unit->bombardStrength();
    }
    return $ret;
  }
}
// quick example classes
class Tank extends Unit { // 坦克
  function addUnit( Unit $unit ) {}
  function removeUnit( Unit $unit ) {}
  function bombardStrength() {
    return 4;
  }
}
class Soldier extends Unit { // 士兵
  function addUnit( Unit $unit ) {}
  function removeUnit( Unit $unit ) {}
  function bombardStrength() {
    return 8;
  }
}
$tank = new Tank();
$tank2 = new Tank();
$soldier = new Soldier();
$army = new Army();
$army->addUnit( $soldier );
$army->addUnit( $tank );
$army->addUnit( $tank2 );
print_r( $army );
print $army->bombardStrength()."\n";
$army->removeUnit( $soldier );
print_r( $army );
print $army->bombardStrength()."\n";
?>

output:

Army Object
(
  [units:Army:private] => Array
    (
      [0] => Soldier Object
        (
        )
      [1] => Tank Object
        (
        )
      [2] => Tank Object
        (
        )
    )
)
16
Army Object
(
  [units:Army:private] => Array
    (
      [1] => Tank Object
        (
        )
      [2] => Tank Object
        (
        )
    )
)
8

添加异常处理

<?php
abstract class Unit {
  abstract function addUnit( Unit $unit );
  abstract function removeUnit( Unit $unit );
  abstract function bombardStrength();
}
class Army extends Unit {
  private $units = array();
  function addUnit( Unit $unit ) {
    if ( in_array( $unit, $this->units, true ) ) {
      return;
    }
    $this->units[] = $unit;
  }
  function removeUnit( Unit $unit ) {
    // >= php 5.3
    //$this->units = array_udiff( $this->units, array( $unit ),
    //        function( $a, $b ) { return ($a === $b)?0:1; } );
    // < php 5.3
    $this->units = array_udiff( $this->units, array( $unit ),
            create_function( '$a,$b', 'return ($a === $b)?0:1;' ) );
  }
  function bombardStrength() {
    $ret = 0;
    foreach( $this->units as $unit ) {
      $ret += $unit->bombardStrength();
    }
    return $ret;
  }
}
class UnitException extends Exception {}
class Archer extends Unit {
  function addUnit( Unit $unit ) {
    throw new UnitException( get_class($this)." is a leaf" );
  }
  function removeUnit( Unit $unit ) {
    throw new UnitException( get_class($this)." is a leaf" );
  }
  function bombardStrength() {
    return 4;
  }
}
$archer = new Archer();
$archer2 = new Archer();
$archer->addUnit( $archer2 );
?>

output:

Fatal error: Uncaught exception 'UnitException' with message 'Archer is a leaf'

点评:组合模式中的一切类都共享同一个父类型,可以轻松地在设计中添加新的组合对象或局部对象,而无需大范围地修改代码。

最终的效果,逐步优化(完美):

<?php
class UnitException extends Exception {}
abstract class Unit {
  abstract function bombardStrength();
  function addUnit( Unit $unit ) {
    throw new UnitException( get_class($this)." is a leaf" );
  }
  function removeUnit( Unit $unit ) {
    throw new UnitException( get_class($this)." is a leaf" );
  }
}
class Archer extends Unit {
  function bombardStrength() {
    return 4;
  }
}
class LaserCannonUnit extends Unit {
  function bombardStrength() {
    return 44;
  }
}
class Army extends Unit {
  private $units = array();
  function addUnit( Unit $unit ) {
    if ( in_array( $unit, $this->units, true ) ) {
      return;
    }
    $this->units[] = $unit;
  }
  function removeUnit( Unit $unit ) {
    // >= php 5.3
    //$this->units = array_udiff( $this->units, array( $unit ),
    //        function( $a, $b ) { return ($a === $b)?0:1; } );
    // < php 5.3
    $this->units = array_udiff( $this->units, array( $unit ),
            create_function( '$a,$b', 'return ($a === $b)?0:1;' ) );
  }
  function bombardStrength() {
    $ret = 0;
    foreach( $this->units as $unit ) {
      $ret += $unit->bombardStrength();
    }
    return $ret;
  }
}
// create an army
$main_army = new Army();
// add some units
$main_army->addUnit( new Archer() );
$main_army->addUnit( new LaserCannonUnit() );
// create a new army
$sub_army = new Army();
// add some units
$sub_army->addUnit( new Archer() );
$sub_army->addUnit( new Archer() );
$sub_army->addUnit( new Archer() );
// add the second army to the first
$main_army->addUnit( $sub_army );
// all the calculations handled behind the scenes
print "attacking with strength: {$main_army->bombardStrength()}\n";
?>

output:

attacking with strength: 60

更牛逼的组合处理,

<?php
abstract class Unit {
  function getComposite() {
    return null;
  }
  abstract function bombardStrength();
}
abstract class CompositeUnit extends Unit { // 抽象类继承抽象类
  private $units = array();
  function getComposite() {
    return $this;
  }
  protected function units() {
    return $this->units;
  }
  function removeUnit( Unit $unit ) {
    // >= php 5.3
    //$this->units = array_udiff( $this->units, array( $unit ),
    //        function( $a, $b ) { return ($a === $b)?0:1; } );
    // < php 5.3
    $this->units = array_udiff( $this->units, array( $unit ),
            create_function( '$a,$b', 'return ($a === $b)?0:1;' ) );
  }
  function addUnit( Unit $unit ) {
    if ( in_array( $unit, $this->units, true ) ) {
      return;
    }
    $this->units[] = $unit;
  }
}
class Army extends CompositeUnit {
  function bombardStrength() {
    $ret = 0;
    foreach( $this->units as $unit ) {
      $ret += $unit->bombardStrength();
    }
    return $ret;
  }
}
class Archer extends Unit {
  function bombardStrength() {
    return 4;
  }
}
class LaserCannonUnit extends Unit {
  function bombardStrength() {
    return 44;
  }
}
class UnitScript {
  static function joinExisting( Unit $newUnit,
                 Unit $occupyingUnit ) { // 静态方法,直接通过类名来使用
    $comp;
    if ( ! is_null( $comp = $occupyingUnit->getComposite() ) ) { // 军队合并处理
      $comp->addUnit( $newUnit );
    } else { // 士兵合并处理
      $comp = new Army();
      $comp->addUnit( $occupyingUnit );
      $comp->addUnit( $newUnit );
    }
    return $comp;
  }
}
$army1 = new Army();
$army1->addUnit( new Archer() );
$army1->addUnit( new Archer() );
$army2 = new Army();
$army2->addUnit( new Archer() );
$army2->addUnit( new Archer() );
$army2->addUnit( new LaserCannonUnit() );
$composite = UnitScript::joinExisting( $army2, $army1 );
print_r( $composite );
?>

output:

Army Object
(
  [units:CompositeUnit:private] => Array
    (
      [0] => Archer Object
        (
        )
      [1] => Archer Object
        (
        )
      [2] => Army Object
        (
          [units:CompositeUnit:private] => Array
            (
              [0] => Archer Object
                (
                )
              [1] => Archer Object
                (
                )
              [2] => LaserCannonUnit Object
                (
                )
            )
        )
    )
)

点评:Unit 基础,CompositeUnit复合中实现add与remove。军队继承Composite,射手继承Archer。这样射手中就不会有多余的add与remove方法了。

装饰模式

装饰模式帮助我们改变具体组件的功能。

看例子

<?php
abstract class Tile { // 砖瓦
  abstract function getWealthFactor(); // 获取财富
}
class Plains extends Tile { // 平原
  private $wealthfactor = 2;
  function getWealthFactor() {
    return $this->wealthfactor;
  }
}
class DiamondPlains extends Plains { // 钻石地段
  function getWealthFactor() {
    return parent::getWealthFactor() + 2;
  }
}
class PollutedPlains extends Plains { // 污染地段
  function getWealthFactor() {
    return parent::getWealthFactor() - 4;
  }
}
$tile = new PollutedPlains();
print $tile->getWealthFactor();
?>

output:
-2

点评:不具有灵活性,我们不能同时获得钻石与被污染的土地的资金情况。

装饰模式使用组合和委托而不是只使用继承来解决功能变化的问题。

看例子:

<?php
abstract class Tile {
  abstract function getWealthFactor();
}
class Plains extends Tile {
  private $wealthfactor = 2;
  function getWealthFactor() {
    return $this->wealthfactor;
  }
}
abstract class TileDecorator extends Tile { // 装饰
  protected $tile;
  function __construct( Tile $tile ) {
    $this->tile = $tile;
  }
}
class DiamondDecorator extends TileDecorator { // 钻石装饰
  function getWealthFactor() {
    return $this->tile->getWealthFactor()+2;
  }
}
class PollutionDecorator extends TileDecorator { // 污染装饰
  function getWealthFactor() {
    return $this->tile->getWealthFactor()-4;
  }
}
$tile = new Plains();
print $tile->getWealthFactor(); // 2
$tile = new DiamondDecorator( new Plains() );
print $tile->getWealthFactor(); // 4
$tile = new PollutionDecorator(
       new DiamondDecorator( new Plains() ));
print $tile->getWealthFactor(); // 0
?>

output:
2
4
0

点评:这个模型具有扩展性。我们不需要创建DiamondPollutionPlains对象就可以构建一个钻石被污染的对象。

一个更逼真的例子

<?php
class RequestHelper{} // 请求助手
abstract class ProcessRequest { // 进程请求
  abstract function process( RequestHelper $req );
}
class MainProcess extends ProcessRequest { // 主进程
  function process( RequestHelper $req ) {
    print __CLASS__.": doing something useful with request\n";
  }
}
abstract class DecorateProcess extends ProcessRequest { // 装饰进程
  protected $processrequest;
  function __construct( ProcessRequest $pr ) { // 引用对象,委托
    $this->processrequest = $pr;
  }
}
class LogRequest extends DecorateProcess { // 日志请求
  function process( RequestHelper $req ) {
    print __CLASS__.": logging request\n"; // 当前类,有点递归的感觉
    $this->processrequest->process( $req );
  }
}
class AuthenticateRequest extends DecorateProcess { // 认证请求
  function process( RequestHelper $req ) {
    print __CLASS__.": authenticating request\n";
    $this->processrequest->process( $req );
  }
}
class StructureRequest extends DecorateProcess { // 组织结构请求
  function process( RequestHelper $req ) {
    print __CLASS__.": structuring request\n";
    $this->processrequest->process( $req );
  }
}
$process = new AuthenticateRequest( new StructureRequest(
                  new LogRequest (
                  new MainProcess()
                  ))); // 这样可以很灵活的组合进程的关系,省去很多重复的继承
$process->process( new RequestHelper() );
print_r($process);
?>

output:

AuthenticateRequest: authenticating request
StructureRequest: structuring request
LogRequest: logging request
MainProcess: doing something useful with request
AuthenticateRequest Object
(
  [processrequest:protected] => StructureRequest Object
    (
      [processrequest:protected] => LogRequest Object
        (
          [processrequest:protected] => MainProcess Object
            (
            )
        )
    )
)

点评:这里有一种递归的感觉,一层调用一层。模式是牛人总结出来用于灵活的解决一些现实问题的。牛!给开发多一点思路。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
php下HTTP Response中的Chunked编码实现方法
Nov 19 PHP
PHP优于Node.js的五大理由分享
Sep 15 PHP
php排序算法(冒泡排序,快速排序)
Oct 09 PHP
php增删改查示例自己写的demo
Sep 04 PHP
PHP判断一个gif图片是否为动态图片的方法
Nov 19 PHP
PHP中防止SQL注入方法详解
Dec 25 PHP
laravel 中如何使用ajax和vue总结
Aug 16 PHP
laravel通过创建自定义artisan make命令来新建类文件详解
Aug 17 PHP
Ajax中的JSON格式与php传输过程全面解析
Nov 14 PHP
PHP重置数组为连续数字索引的几种方式总结
Mar 12 PHP
Laravel5.4简单实现app接口Api Token认证方法
Aug 29 PHP
php框架知识点的整理和补充
Mar 01 PHP
PHP与jquery实时显示网站在线人数实例详解
Dec 02 #PHP
谈谈php对接芝麻信用踩的坑
Dec 01 #PHP
PHP自定义函数获取汉字首字母的方法
Dec 01 #PHP
phpmailer绑定邮箱的实现方法
Dec 01 #PHP
thinkPHP实现多字段模糊匹配查询的方法
Dec 01 #PHP
thinkPHP商城公告功能开发问题分析
Dec 01 #PHP
thinkPHP订单数字提醒功能的实现方法
Dec 01 #PHP
You might like
php date()日期时间函数详解
2010/05/16 PHP
PHP 以POST方式提交XML、获取XML,解析XML详解及实例
2016/10/26 PHP
Laravel框架FormRequest中重写错误处理的方法
2019/02/18 PHP
laravel Task Scheduling(任务调度)在windows下的使用详解
2019/10/22 PHP
PHP的HTTP客户端Guzzle简单使用方法分析
2019/10/30 PHP
JavaScript 解析读取XML文档 实例代码
2009/07/07 Javascript
javascript EXCEL 操作类代码
2009/07/30 Javascript
jQuery与其它库冲突的解决方法
2010/06/25 Javascript
jQuery中document与window以及load与ready 区别详解
2014/12/29 Javascript
javascript中函数作为参数调用的方法
2015/02/09 Javascript
javascript将中国数字格式转换成欧式数字格式的简单实例
2016/08/02 Javascript
微信小程序 循环及嵌套循环的使用总结
2017/09/26 Javascript
nodejs前端模板引擎swig入门详解
2018/05/15 NodeJs
基于Vue组件化的日期联动选择器功能的实现代码
2018/11/30 Javascript
vue elementUI table 自定义表头和行合并的实例代码
2019/05/22 Javascript
Vue Router的手写实现方法实现
2020/03/02 Javascript
Python中的zip函数使用示例
2015/01/29 Python
python+VTK环境搭建及第一个简单程序代码
2017/12/13 Python
Python实现的建造者模式示例
2018/08/06 Python
PyTorch中Tensor的维度变换实现
2019/08/18 Python
Django filter动态过滤与排序实现过程解析
2020/11/26 Python
Python3.9.0 a1安装pygame出错解决全过程(小结)
2021/02/02 Python
CSS3制作翻转效果_动力节点Java学院整理
2017/07/11 HTML / CSS
HTML5中FileReader接口使用方法实例详解
2017/08/26 HTML / CSS
BONIA波尼亚新加坡官网:皮革手袋,鞋类和配件
2016/08/25 全球购物
Guess荷兰官网:美国服饰品牌
2020/01/22 全球购物
Ibatis的核心配置文件都有什么
2014/09/08 面试题
MYSQL相比于其他数据库有哪些特点
2013/07/19 面试题
腾讯公司的一个sql题
2013/01/22 面试题
高校毕业生登记表自我鉴定
2013/11/03 职场文书
中学生团员自我评价分享
2013/12/07 职场文书
2015年社区统计工作总结
2015/04/21 职场文书
求职意向书范本
2015/05/11 职场文书
师范生小学见习总结
2015/06/23 职场文书
安全生产协议书
2016/03/22 职场文书
导游词之永济鹳雀楼
2020/01/16 职场文书