六. PHP模式设计----让面向对象编程更加灵活的模式

来源:互联网 发布:国考如何备考 知乎 编辑:程序博客网 时间:2024/05/17 02:53
*问题来源
下面代码中,当军队功能变得越来越复杂时(比如支持合并,拆分),需要修改的地方就越来越多,类似军队的其他类也一样道理,维护起来很麻烦
//以"文明"游戏为背景...
//*战斗单元类
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 $armys=array();
    
    //添加单元
    function addUnit(Unit $unit){
        if(!empty($unit)){
            array_push($this->units$unit);
        }
    }
    //添加军队
    function addArmy(Army $army){
    if(!empty($army)){
            array_push($this->armys$army);
        }
    }
    //计算总强度
    function bombardStrength(){
        $ret=0;
        foreach ($this->units as $unit){
            $ret+=$unit->bombardStrength();
        }
        //当支持军队合并时,则计算总强度需要增加下面代码
        foreach ($this->armys as $army){
            $ret+=$army->bombardStrength();
        }
        return $ret;
    }
    //移动能力,防御能力...省略
}
//运兵船:一个类似军队的单元,它具备10个战斗单元,有攻击力
class TroopCarrier{
    //具备和军队差不多的方法和属性
}
$armyA=new Army();
$armyA->addUnit(new Archer());
$armyA->addUnit(new LaserCannonUnit());
$armyB=new Army();
$armyB->addUnit(new Archer());
$armyB->addUnit(new Archer());
$armyA->addArmy($armyB);
print $armyA->bombardStrength();//==>56

1 组合模式
 组合模式用于解决上面例子出现的那类问题....(接下去有几个修正的例子)
//以"文明"游戏为背景...
//运用组合模式,把军队和运兵车也当作Unit的组合对象
//*战斗单元类
abstract class Unit{
    abstract function addUnit(Unit $unit);
    abstract function removeUnit(Unit $unit);
    //攻击强度
    abstract function bombardStrength();
}
//射手
class Archer extends Unit{
    function bombardStrength(){
        return 4;
    }
    function addUnit(Unit $unit){
        
    }
    function removeUnit(Unit $unit){
        
    }
}
//激光塔
class LaserCannonUnit extends Unit{
    function bombardStrength(){
        return 44;
    }
    function addUnit(Unit $unit){
    
    }
    function removeUnit(Unit $unit){
    
    }
}
//军队:由战斗单元组成
class Army extends Unit{
    private $units=array();
    
    //添加单元
    function addUnit(Unit $unit){
        if(!empty($unit)){
            if(in_array($unit$this->units,true)){
                return;
            }
            array_push($this->units$unit);
        }
    }
    function removeUnit(Unit $unit){
        $this->units=array_udiff($this->unitsarray($unit), function ($a,$b){return ($a===$b?0:1);});
    }
    //计算总强度
    function bombardStrength(){
        $ret=0;
        foreach ($this->units as $unit){
            $ret+=$unit->bombardStrength();
        }
        return $ret;
    }
    //移动能力,防御能力...省略
}
//运兵船:一个类似军队的单元,它具备10个战斗单元,有攻击力
class TroopCarrier extends Unit{
    //具备和军队差不多的方法和属性
    function bombardStrength(){
    }
    function addUnit(Unit $unit){
    
    }
    function removeUnit(Unit $unit){
    
    }
}
$main_army=new Army();
//添加一些Unit对象
$main_army->addUnit(new Archer());
$main_army->addUnit(new LaserCannonUnit());
$sub_army=new Army();
$sub_army->addUnit(new Archer());
$sub_army->addUnit(new Archer());
$main_army->addUnit($sub_army);
print $main_army->bombardStrength();

*1.修正上一个例子中抽象类强制性的不必要的方法(缺点:子类未被强制要求实现addUnit()等,这是一个大问题)
//以"文明"游戏为背景...
//运用组合模式,把军队和运兵车也当作Unit的组合对象
//*战斗单元类
abstract class Unit{
    function addUnit(Unit $unit){
        return new Exception(get_class($this)." is a leaf");
    }
    function removeUnit(Unit $unit){
        return new Exception(get_class($this)." is a leaf");
    }
    //攻击强度
    abstract function bombardStrength();
}
//射手
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(!empty($unit)){
            if(in_array($unit$this->units,true)){
                return;
            }
            array_push($this->units$unit);
        }
    }
    function removeUnit(Unit $unit){
        $this->units=array_udiff($this->unitsarray($unit), function ($a,$b){return ($a===$b?0:1);});
    }
    //计算总强度
    function bombardStrength(){
        $ret=0;
        foreach ($this->units as $unit){
            $ret+=$unit->bombardStrength();
        }
        return $ret;
    }
    //移动能力,防御能力...省略
}
//运兵船:一个类似军队的单元,它具备10个战斗单元,有攻击力
class TroopCarrier extends Unit{
    //具备和军队差不多的方法和属性
    function bombardStrength(){
    }
    function addUnit(Unit $unit){
    
    }
    function removeUnit(Unit $unit){
    
    }
}
$main_army=new Army();
//添加一些Unit对象
$main_army->addUnit(new Archer());
$main_army->addUnit(new LaserCannonUnit());
$sub_army=new Army();
$sub_army->addUnit(new Archer());
$sub_army->addUnit(new Archer());
$main_army->addUnit($sub_army);
print $main_army->bombardStrength();
print "\n";
print (new Archer())->addUnit(new Archer());

*2. 增加一个继承自Unit的抽象类CompositeUnit,让复杂的类直接继承CompositeUnit,简单类继承Unit,再把复杂类必备的特殊接口放在CompositeUnit类里
//以"文明"游戏为背景...
//运用组合模式,把军队和运兵车也当作Unit的组合对象
//本例子需要解决一个问题,就是如何区分Unit的实例是否支持addUnit等方法?
//解决方案就是在Unit中增加一个方法getComposite(),默认返回null,只有CompositeUnit类的实例才会返回非null
//*战斗单元类
abstract class Unit{
    //攻击强度
    abstract function bombardStrength();
    function getComposite(){
        return null;
    }
}
//复合抽象类
abstract class CompositeUnit extends Unit{
    protected $units=array();
    //可以不用写bombardStrength()
    function getComposite(){
        return $this;
    }
    //添加单元
    function addUnit(Unit $unit){
        if(!empty($unit)){
            if(in_array($unit$this->units,true)){
                return;
            }
            array_push($this->units$unit);
        }
    }
    function removeUnit(Unit $unit){
        $this->units=array_udiff($this->unitsarray($unit), function ($a,$b){return ($a===$b?0:1);});
    }
}
//射手
class Archer extends Unit{
    function bombardStrength(){
        return 4;
    }
}
//激光塔
class LaserCannonUnit extends Unit{
    function bombardStrength(){
        return 44;
    }
}
//军队:由战斗单元组成
class Army extends CompositeUnit{
    //计算总强度
    function bombardStrength(){
        $ret=0;
        foreach ($this->units as $unit){
            $ret+=$unit->bombardStrength();
        }
        return $ret;
    }
    //移动能力,防御能力...省略
}
//运兵船:一个类似军队的单元,它具备10个战斗单元,有攻击力
class TroopCarrier extends CompositeUnit{
    //具备和军队差不多的方法和属性
    function bombardStrength(){
        //Do something...
    }
}
//UnitScript类:用于合并等操作
class UnitScript{
    /**
     * 返回合并后的对象
     * @param Unit $newUnit 新来者
     * @param Unit $occupyingUnit 占据着
     */
    static function joinExisting(Unit $newUnit,Unit $occupyingUnit){
        $comp=$occupyingUnit;
        if(!is_null($comp->getComposite())){
            //该方法不会自动识别到...
            $comp->addUnit($newUnit);
            return $comp;
        }
        $comp=new Army();
        $comp->addUnit($newUnit);
        $comp->addUnit($occupyingUnit);
        return $comp;
    }
}
$unitScript=new UnitScript();
$army=$unitScript->joinExisting(new Archer(), new LaserCannonUnit());
$army=$unitScript->joinExisting($armynew Archer());
print $army->bombardStrength();

2. 装饰模式
       问题背景:如果每一个功能都建立在继承上,比如Tile(区域)为父类,钻石区域和污染区域为子类,这时候若需要一个被污染的钻石区域,那么就需要再定义一个新类出来,问题一旦更复杂,类就会爆炸式增长...
//装饰模式就是使用组合和委托,Decorator类会保存另一个类的实例,这样就可以像套管道一样,一个套
//一个来实现不同的组合功能
abstract class Tile{
    //获取区域收益
    abstract function getWealthFactor();
}
class Plains extends Tile{
    private $wealthFactor=2;
    function getWealthFactor(){
        print "Call ".__CLASS__."\n";
        return $this->wealthFactor;
    }
}
//抽象装饰类
abstract class TileDecorator extends Tile{
    //一个用于保存Tile实例的可继承属性
    protected $tile;
    function __construct(Tile $tile){
        $this->tile=$tile;
    }
}
//钻石装饰类
class DiamondDecorator extends TileDecorator{
    function getWealthFactor(){
        print "Call ".__CLASS__."\n";
        return $this->tile->getWealthFactor()+2;
    }
}
//污染装饰类
class PollutionDecorator extends TileDecorator{
    function getWealthFactor(){
        print "Call ".__CLASS__."\n";
        return $this->tile->getWealthFactor()-4;
    }
}
$tile=new Plains();
print "平原收益为:".$tile->getWealthFactor();//==>2
print "\n";
//用管道方式定义一个被污染的钻石区域
$pollutionDiamon=new PollutionDecorator(new DiamondDecorator(new Plains()));
print "被污染的钻石平原收益为:".$pollutionDiamon->getWealthFactor();//(2+2-4)==>0

3.外观模式
        系统部分功能的实现是利用子系统,所以把这部分系统功能封装成一个单一接口,供外界调用几段过程是代码实现一个几个功能,再建立一个类把这些功能封装在一起,利用过程式代码再实现一个全新的功能.
function getProductFileLines($file){
    return file($file);
}
function getProductObjectFromId($id,$productName){
    return new Product($id,$productName);
}
function getNameFromLine($line){
    if(preg_match("/.*-(.*)\s\d+/"$line,$array)){
        return str_replace('_'' '$array[1]);
    }
    return '';
}
function getIDFromLine($line){
    //$array第一个为完全匹配项(234-),第二个开始为子匹配项(234)  
    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();
    }
    function compile(){
        $aryFile=getProductFileLines($this->file);
        foreach ($aryFile 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("src/myResource.txt");
$facade->getProduct(234);
print_r($facade);
/*=>ProductFacade Object
(
    [products:ProductFacade:private] => Array
        (
            [234] => Product Object
                (
                    [id] => 234
                    [name] => bom jumper
                )
            [445] => Product Object
                (
                    [id] => 445
                    [name] => Cow hat
                )
        )
    [file] => src/myResource.txt
)
*/











0 0
原创粉丝点击