设计模式--PHP实现

一、生成对象:

1、单例模式

确保某一个类只有一个实例,并且提供一个全局访问点。

单例模式具备如下几个特点:

      1、只有一个实例。

      2、能够自我实例化。

      3、提供全局访问点。

 所以说当系统中只需要一个实例对象或者系统中只允许一个公共访问点,除了这个公共访问点外,不能通过其他访问点访问该实例时,可以使用单例模式。
 单例模式的主要优点就是节约系统资源、提高了系统效率,同时也能够严格控制客户对它的访问。也许就是因为系统中只有一个实例,这样就导致了单例类的职责过重,违背了“单一职责原则”,同时也没有抽象类,所以扩展起来有一定的困难。

实现:
class Preferences{
    private $props = array();
    private static $instance;

    private function __construct(){}

    public static function getInstance(){
        if(empty(self::$instance)){
            self::$instance = new Preferences();
        }
        return self::$instance;
    }

    public function setProperty($key,$val){
        $this->props[$key] = $key;
    }

    public function getProperty($key){
        return $this->props[$key];
    }
}

这里写图片描述

2、工厂方法模式

 工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,也就是说工厂方法模式让实例化推迟到子类。

 工厂方法模式非常符合“开闭原则”,当需要增加一个新的产品时,我们只需要增加一个具体的产品类和与之对应的具体工厂即可,无须修改原有系统。同时在工厂方法模式中用户只需要知道生产产品的具体工厂即可,无须关系产品的创建过程,甚至连具体的产品类名称都不需要知道。虽然他很好的符合了“开闭原则”,但是由于每新增一个新产品时就需要增加两个类,这样势必会导致系统的复杂度增加。

实现:
abstract class ApptEncoder{
    abstract function encode();
}

class BloggsApptEncoder extends ApptEncoder{
    public function encode(){
        return "Appointment data encode in BloggsCal format\n";
    }
}

class MegaApptEncoder extends ApptEncoder{
    public function encode(){
        return "Appointment data encode in MegaCal format\n";
    }
}

abstract class CommsManager{
    abstract function getHeaderText();
    abstract function getApptEncoder();
    abstract function getFooterText();
}

class BloggsCommsManager extends CommsManager{
    function getHeaderText(){
        return "BloggsCal header\n";
    }

    function getApptEncoder(){
        return new BloggsCommsManager();
    }

    function get FooterText(){
        return "BloggsCal footer\n";
    }
}

class MegaCommsManager extends CommsManager{
    function getHeaderText(){
        return "MegaCal header\n";
    }

    function getApptEncoder(){
        return new MegaCommsManager();
    }

    function get FooterText(){
        return "MegaCal footer\n";
    }
}

这里写图片描述

3、抽象工厂模式–原型模式

 在我们应用程序可能有某些对象的结构比较复杂,但是我们又需要频繁的使用它们,如果这个时候我们来不断的新建这个对象势必会大大损耗系统内存的,这个时候我们需要使用原型模式来对这个结构复杂又要频繁使用的对象进行克隆。所以原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

 它主要应用与那些创建新对象的成本过大时。它的主要优点就是简化了新对象的创建过程,提高了效率,同时原型模式提供了简化的创建结构。

实现:
class Sea {}
class EarthSea extends Sea {}
class MarsSea extends Sea {}

class Plains {}
class EarthPlains extends Plains {}
class MarsPlains extends Plains {}

class Forest {}
class EarthForest extends Forest {}
class MarsForest extends Forest {}

class TerrainFactory {
    private $sea;
    private $plains;
    private $forest;

    function __construct(Sea $sea, Plains $plains, Forest $forest ) {
        $this->$sea = $sea;
        $this->$plains = $plains;
        $this->$forest = $forest;
    }

    function getSea() {
        return clone $this->sea;
    }

    function getPlains() {
        return clone $this->plains;
    }

    function getForest() {
        return clone $this->forest;
    }
}

$factory =  new TerrainFactory(new EarthSea(), new EarthPlains(), new EarthForest() );

print_r($factory->getSea() );

二、组织对象和类:

1、组合模式

  组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次。它定义了如何将容器对象和叶子对象进行递归组合,使得客户在使用的过程中无须进行区分,可以对他们进行一致的处理。
  在使用组合模式中需要注意一点也是组合模式最关键的地方:叶子对象和组合对象实现相同的接口。这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。
  特殊对象越多,组合模式的弊端越大;在大部分局部对象可互换的情况下,可选用组合模式。对象难以持久化到关系型数据库,但非常适合持久化为XML。

实现:
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 Archer extends Unit {
    function bombardStrength() {
        return 4;
    }
}

class LaserCanon 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) {
        $this->units = array_udiff($this->units, array($unit),
                    function($a,$b){return ($a === $b)?0:1} );
    }

    function bombardStrength() {
        $ret = 0;
        foreach($this->units as $unit) {
            $ret += $unit->bombardStrength();
        }
        return $ret;
    }
}

class TroopCarrier extends Unit {
    private $units = array();

    function addUnit(Unit $unit) {
        if(in_array($unit, $this->units,true)) {
            return;
        }

        $this->units[] = $unit;
    }

    function removeUnit(Unit $unit) {
        $this->units = array_udiff($this->units, array($unit),
                    function($a,$b){return ($a === $b)?0:1} );
    }

    function bombardStrength() {
        $ret = 0;
        foreach($this->units as $unit) {
            $ret += $unit->bombardStrength();
        }
        return $ret;
    }
}

这里写图片描述

2、装饰模式

  装饰者模式,动态地将责任附加到对象上。可有效地解决“类爆炸”现象,关联同一级的子类,减少为关联同一级子类而产生的冗余子类。

实现:
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 PollutionDecorator(new DiamondDecorator(new Plains()));
print $tile->getWealthFactor();

这里写图片描述

3、外观模式

外观模式提供了一个统一的接口,用来访问子系统中的一群接口。

三、类或者对象的交互和职责分配:

1、策略模式

  当类必须支持同一个接口的多种实现时,最好的办法就是提取出这些实现,并将它们放置在自己的类型中,而不是通过继承原有的类去支持这些实现。
  定义了算法族,分别封装起来,让他们之前可以互相转换,此模式让该算法的变化独立于使用算法的客户。

实现:

abstract class Question {
    protected $prompt;
    protected $marker;

    function __construct($prompt,Marker $marker) {
        $this->marker = $marker;
        $this->prompt = $prompt;
    }

    function mark($response) {
        return $this->marker->mark($response);
    }
}

class TextQuestion extends Question {

}

class AVQuestion extends Question {

} 

abstract class Marker {
    protected $test;

    function __construct($test) {
        $this->test = $test;
    }

    abstract function mark($response);
}

class MarkLogicMarker extends Marker {
    private $engine;
    function __construct($test) {
        parent::__construct($test);
    }

    function mark($response) {
        return true;
    }
}

class MatchMarker extends Marker {
    function mark($response) {
        return ($this->test == $response);
    }
}

class RegexpMarker extends Marker {
    function mark($response) {
        return (preg_match($this->test,$response));
    }
}

//客户端代码
$markers = array(  new RegexpMarker("/f.ve/"),
                    new MatchMarker("five"),
                    new MarkLogicMarker('$input equal "five"')
            );

foreach($markers as $marker) {
    print get_class($marker)."\n";
    $question = new TextQuestion("how many beans make five",$marker);
    foreach(array("five","four") as $response) {
        print "\tresponse: $response: ";
        if($question->mark($response)) {
            print "well done\n";
        }
        else{
            print "never mind\n";
        }
    }
}

//output:
//RegexpMarker
//  response: five: well down
//  response: four: never mind
//MatchMarker
//  response: five: well down
//  response: four: never mind
//MarkLogicMarker
//  response: five: well down
//  response: four: well down

这里写图片描述

2、观察者模式

  观察者模式的核心是把客户元素(观察者)从一个中心类(主体)中分离开来。当主体知道事件发生时,观察者需要被通知到。同时,我们并不希望将主体与观察者之间的关系进行硬编码。观察者和被观察者是抽象耦合的。

使用场景:
(1)一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
(2)一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
(3)一个对象必须通知其他对象,而并不知道这些对象是谁。
(4)需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

实现:
interface Observable {
    function attach(Observer $observer);
    function detach(Observer $observer);
    function notify();
}

class Login implements Observable {
    const LOGIN_USER_UNKNOWN = 1;
    const LOGIN_WRONG_PASS = 2;
    const LOGIN_ACCESS = 3;
    private $status = array();

    private $observers;

    function __construct() {

        $this->observers = array();

    }

    function attach(Observer $observer) {
        $this->observers[] = $observer;
    }

    function detach(Observer $observer) {
        $this->observers = array_udiff($this->observers,array($observer),function($a,$b) {return ($a === $b)?0:1; });
    }

    function notify() {
        foreach ($this->observers as $obs) {
            $obs->update($this);
        }
    }

    function handleLogin($user, $pass, $ip ) {
        switch (rand(1,3)) {
            case 1:
                $this->setStatus(self::LOGIN_USER_UNKNOWN, $user, $ip);
                $ret = false; break;
            case 2:
                $this->setStatus(self::LOGIN_WRONG_PASS, $user, $ip);
                $ret = false; break;
            case 3:
                $this->setStatus(self::LOGIN_ACCESS, $user, $ip);
                $ret = true; break;
        }
        $this->notify();
        return $ret;
    }

    private function setStatus($status, $user, $ip) {
        $this->status = array($status, $user, $ip);
    }

    function getStatus() {
        return $this->status;
    }

}

interface Observer {
    function update(Observable $observable );
}

abstract class LoginObserver implements Observer {
    private $login;
    function __construct(Login $login ) {
        $this->login = $login;
        $login->attach($this);
    }

    function update(Observable $observable) {
        if($observable === $this->login) {
            $this->doUpdate($observable);
        }
    }

    abstract function doUpdate(Login $login);
}

class SecurityMonitor extends LoginObserver {
    function doUpdate(Login $login ) {
        $status = $login->getStatus();
        if($status[0] == Login::LOGIN_WRONG_PASS ) {
            //send email to administrator
            print __CLASS__.":\tsending mail to sysadmin\n";
        }
    }
}

class GeneralLogger extends LoginObserver {
    function doUpdate(Login $login ) {
        $status = $login->getStatus();
        print __CLASS__.":\tadd login data to log\n";
    }
}

class PartnershipTool extends LoginObserver {
    function doUpdate(Login $login ) {
        $status = $login->getStatus();
        print __CLASS__.":\tset cookie if IP matches a list\n";
    }
}

$login = new Login();
new SecurityMonitor($login);
new GeneralLogger($login);
new PartnershipTool($login);

$login->handleLogin("Hello","123","127.0.0.1");

这里写图片描述

3、访问者模式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值