结构型模式
结构型模式:组合可比继承提供更多的灵活性。
- 组合模式(Composite): 将一组对象组合为可像单个对象一样被使用的结构。
- 装饰模式(Decorator): 通过在运行时合并对象来扩展功能的一种灵活机制。
- 外观模式(Facade): 为复杂或多边的系统创建一个简单的接口。
组合模式
- 意图:将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
- 动机:一个游戏中的军队,可能有很多可移动的战斗单元组成,步兵、骑兵等。他们一起移动、进攻、防守。可能会有其他部队加入,也可能加入的部队要再分拆。
- 实现:组合模式定义了一个单根继承体系,使得具有截然不同值得的集合可以并肩工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| #!/bin/env/php <?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 );
|
装饰模式
- 意图:动态地给一个对象添加一些额外的职责。就增加功能来说, 更为灵活。
- 动机:将所有功能都建立在继承体系上会导致系统中的类“爆炸式”增多,更糟糕的是对继承树上下不同分支做相同修改,会造成代码重复。例如:游戏中定义Tile(区域)定义,并且定义的到此区域内财富的方法getWealthFactor, Plain(平地)继承自Tile。如果我们需要在定义污染的平地和地表有钻石的平台,则需要再从Plain继承编写子类。区域的种类增多,则子类也会随之增多,继承树也会越来越庞大。则问题来了,此时,这个结构就显得不够灵活。
- 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| #!/bin/env/php <?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
|
外观模式
- 意图:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 动机:当系统中引入第三方子系统,而且系统过于深入的调用子系统代码。当子系统代码不断变化,你的系统又在很多地方与子系统代码交互。随着子系统的发展,我们的代码维护会越来越困难。
- 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| !#/bin/env/php <?php
function getProductFileLines( $file ) { return file( $file ); }
function getProductObjectFromId( $id, $productname ) { // some kind of database lookup return new Product( $id, $productname ); }
function getNameFromLine( $line ) { if ( preg_match( "/.*-(.*)\s\d+/", $line, $array ) ) { return str_replace( '_',' ', $array[1] ); } return ''; }
function getIDFromLine( $line ) { if ( preg_match( "/^(\d{1,3})-/", $line, $array ) ) { return $array[1]; } return -1; }
class Product { public $id; public $name; function __construct( $id, $name ) { $this->id = $id; $this->name = $name; } }
class ProductFacade { private $products = array();
function __construct( $file ) { $this->file = $file; $this->compile(); }
private function compile() { $lines = getProductFileLines( $this->file ); foreach ( $lines as $line ) { $id = getIDFromLine( $line ); $name = getNameFromLine( $line ); $this->products[$id] = getProductObjectFromID( $id, $name ); } }
function getProducts() { return $this->products; }
function getProduct( $id ) { return $this->products[$id]; } }
$facade = new ProductFacade( 'test.txt' ); $object = $facade->getProduct( 234 );
print_r( $object );
|