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中使用sockets:从新闻组中获取文章
Oct 09 PHP
操作Oracle的php类
Oct 09 PHP
PHP中foreach循环中使用引用要注意的地方
Jan 02 PHP
eaglephp使用微信api接口开发微信框架
Jan 09 PHP
删除html标签得到纯文本可处理嵌套的标签
Apr 28 PHP
使用PHP和HTML5 FormData实现无刷新文件上传教程
Sep 06 PHP
PHP接收json 并将接收数据插入数据库的实现代码
Dec 01 PHP
讲解WordPress开发中一些常用的debug技巧
Dec 18 PHP
PHP中的使用curl发送请求(GET请求和POST请求)
Feb 08 PHP
PHP实现防止表单重复提交功能【基于token验证】
May 24 PHP
tp5框架基于ajax实现异步删除图片的方法示例
Feb 10 PHP
Laravel框架源码解析之反射的使用详解
May 14 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 金额数字转换成英文
2010/05/06 PHP
php的array_multisort()使用方法介绍
2012/05/16 PHP
php curl选项列表(超详细)
2013/07/01 PHP
浅谈php扩展imagick
2014/06/02 PHP
使用PHP json_decode可能遇到的坑与解决方法
2017/08/03 PHP
php防止表单重复提交实例讲解
2019/02/11 PHP
PHP+fiddler抓包采集微信文章阅读数点赞数的思路详解
2019/12/20 PHP
原生Js页面滚动延迟加载图片实现原理及过程
2013/06/24 Javascript
jQuery实现回车键(Enter)切换文本框焦点的代码实例
2014/05/05 Javascript
JavaScript设计模式之工厂模式和构造器模式
2015/02/11 Javascript
JavaScript弹出对话框的三种方式
2016/03/23 Javascript
javascript基础知识之html5轮播图实例讲解(44)
2017/02/17 Javascript
基于EasyUI的基础之上实现树形功能菜单
2017/06/28 Javascript
解决webpack无法通过IP地址访问localhost的问题
2018/02/22 Javascript
解决vue页面DOM操作不生效的问题
2018/03/17 Javascript
详解Vue组件之间通信的七种方式
2019/04/14 Javascript
vue日历/日程提醒/html5本地缓存功能
2019/09/02 Javascript
[01:14]辉夜杯战队访谈宣传片—NEWBEE.Y
2015/12/26 DOTA
python使用正则表达式的search()函数实现指定位置搜索功能
2017/11/10 Python
python读取中文txt文本的方法
2018/04/12 Python
Python实现的knn算法示例
2018/06/14 Python
python实现简单tftp(基于udp协议)
2018/07/30 Python
用pycharm开发django项目示例代码
2018/10/24 Python
pygame游戏之旅 创建游戏窗口界面
2018/11/20 Python
Python算法中的时间复杂度问题
2019/11/19 Python
简单了解python调用其他脚本方法实例
2020/03/26 Python
python3 os进行嵌套操作的实例讲解
2020/11/19 Python
HTML5自定义mp3播放器源码
2020/01/06 HTML / CSS
canvas 绘图时位置偏离的问题解决
2020/09/16 HTML / CSS
股份转让协议书
2014/04/12 职场文书
消防安全责任书范本
2014/04/15 职场文书
2015年上半年物业工作总结
2015/03/30 职场文书
优秀的商业计划书,让融资一步到位
2019/05/07 职场文书
为什么说餐饮很难做,是因为你不了解这些新规则
2019/08/20 职场文书
python 如何执行控制台命令与操作剪切板
2021/05/20 Python
SQL基础的查询语句
2021/11/11 MySQL