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入门学习的几个不错的实例代码
Jul 13 PHP
PHP通用分页类page.php[仿google分页]
Aug 31 PHP
PHP 获取目录下的图片并随机显示的代码
Dec 28 PHP
UCenter中的一个可逆加密函数authcode函数代码
Jul 20 PHP
php加速器eAccelerator的配置参数、API详解
May 05 PHP
php中使用Ajax时出现Error(c00ce56e)的详细解决方案
Nov 03 PHP
Yii2组件之多图上传插件FileInput的详细使用教程
Jun 20 PHP
Yii视图操作之自定义分页实现方法
Jul 14 PHP
php实现有序数组打印或排序的方法【附Python、C及Go语言实现代码】
Nov 10 PHP
Laravel中encrypt和decrypt的实现方法
Sep 24 PHP
php+Ajax无刷新验证用户名操作实例详解
Mar 04 PHP
详解PHP的抽象类和抽象方法以及接口总结
Mar 15 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关联数组快速排序的方法
2015/04/17 PHP
php强制用户转向www域名的方法
2015/06/19 PHP
调用WordPress函数统计文章访问量及PHP原生计数器的实现
2016/03/21 PHP
php获取ip及网址的简单方法(必看)
2017/04/01 PHP
如何让页面在打开时自动刷新一次让图片全部显示
2012/12/17 Javascript
解析使用JS 清空File控件的路径值
2013/07/08 Javascript
js动态设置鼠标事件示例代码
2013/10/30 Javascript
jQuery图片轮播滚动切换代码分享
2020/04/20 Javascript
javascript移动开发中touch触摸事件详解
2016/03/18 Javascript
深入理解jQuery之防止冒泡事件
2016/05/24 Javascript
分享JS数组求和与求最大值的方法
2016/08/11 Javascript
jQuery可见性过滤选择器用法示例
2016/09/09 Javascript
微信小程序 loading 详解及实例代码
2016/11/09 Javascript
jquery删除数组中重复元素
2016/12/05 Javascript
JS基于面向对象实现的选项卡效果示例
2016/12/20 Javascript
JQuery 封装 Ajax 常用方法(推荐)
2017/05/21 jQuery
基于vue.js中事件修饰符.self的用法(详解)
2018/02/23 Javascript
点击按钮弹出模态框的一系列操作代码实例
2019/03/29 Javascript
用JS实现选项卡
2020/03/23 Javascript
vue项目里面引用svg文件并给svg里面的元素赋值
2020/08/17 Javascript
[45:56]Ti4正赛第一天 VG vs NEWBEE 3
2014/07/19 DOTA
[59:35]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#1COL VS Alliance第二局
2016/03/04 DOTA
修改Python的pyxmpp2中的主循环使其提高性能
2015/04/24 Python
python 专题九 Mysql数据库编程基础知识
2017/03/16 Python
Django如何实现内容缓存示例详解
2017/09/24 Python
python 列表降维的实例讲解
2018/06/28 Python
在python下读取并展示raw格式的图片实例
2019/01/24 Python
在Python 中实现图片加框和加字的方法
2019/01/26 Python
Pytorch中Tensor与各种图像格式的相互转化详解
2019/12/26 Python
Python将list元素转存为CSV文件的实现
2020/11/16 Python
Corelle官方网站:购买康宁餐具
2016/11/02 全球购物
名人演讲稿范文
2013/12/28 职场文书
活动策划邀请函
2014/02/06 职场文书
KTV员工管理制度
2015/08/06 职场文书
Python集合的基础操作
2021/11/01 Python
Python 匹配文本并在其上一行追加文本
2022/05/11 Python