设计模式-php实现

前言

在实现具体的模式前,我想说大家应该了解的的一些php基础,先来复习几个小问题:

  1. 抽象类:

    是指在 class 前加了 abstract 关键字且存在抽象方法(在类方法 function 关键字前加了 abstract 关键字)的类。抽象类不能被直接实例化。抽象类中只定义(或部分实现)子类需要的方法。
    子类可以通过继承抽象类并通过实现抽象类中的所有抽象方法,使抽象类具体化。如果子类需要实例化,前提是它实现了抽象类中的所有抽象方法。如果子类没有全部实现抽象类中的所有抽象方法,那么该子类也是一个抽象类,必须在 class 前面加上 abstract 关键字,并且不能被实例化。
    注意:
    抽象类 抽象方法 B(),那么 继承该抽象类 实现B() 方法的访问控制不能比 抽象类 抽象方法 B() 的访问控制更严格,也就是说:抽象类 抽象方法 B() 不能为Private 最少为Protected;

  2. Interface(接口)

    接口用关键字 interface 来声明。抽象类提供了具体实现的标准,而接口则是纯粹的模版。接口只定义功能,而不包含实现的内容。
    interface 是完全抽象的,只能声明方法,而且只能声明 public 的方法,不能声明 private 及 protected的方法,不能定义方法体,也不能声明实例变量 。然而, interface 却可以声明常量变量 。但将常量变量放在 interface中违背了其作为接口的作用而存在的宗旨,也混淆了 interface 与类的不同价值。如果的确需要,可以将其放在相应的 abstractclass 或 Class 中。任何实现接口的类都要实现接口中所定义的所有方法,否则该类必须声明为 abstract。一个类可以在声明中使用 implements关键字来实现某个接口。这么做之后,实现接口的具体过程和继承一个仅包含抽象方法的抽象类是一样的。一个类可以同时继承一个父类和实现任意多个接口。extends 子句应该在 implements 子句之前。
    PHP 只支持继承自一个父类,因此 extends关键字后只能跟一个类名。接口不可以实现另一个接口,但可以继承多个。

  3. Abstract Class与Interface的异同相同点

    相同点:
    (a)两者都是抽象类,都不能实例化。
    (b)interface实现类及 abstract class 的子类都必须要实现已经声明的抽象方法。
    不同点:
    (a)interface 需要实现,要用implements ,而 abstract class 需要继承,要用 extends 。 一个类可以实现多个 interface
    ,但一个类只能继承一个 abstract class 。
    (b)interface 强调特定功能的实现,而 abstract class强调所属关系。
    ©尽管 interface 实现类及 abstract class的子类都必须要实现相应的抽象方法,但实现的形式不同。 interface 中的每一个方法都是抽象方法,都只是声明的(declaration, 没有方法体 ) ,实现类必须要实现。
    (d)而 abstract class 的子类可以有选择地实现。这个选择有两点含义:
    abstract class 中并非所有的方法都是抽象的,只有那些冠有 abstract 的方法才是抽象的,子类必须实现。那些没有 abstract 的方法,在 abstract class 中必须定义方法体;
    abstract class 的子类在继承它时,对非抽象方法既可以直接继承,也可以覆盖;而对抽象方法,可以选择实现,也可以留给其子类来实现,但此类必须也声明为抽象类。既是抽象类,当然也不能实例化。
    abstract class 是 interface 与 class 的中介。 abstract class 在 interface 及 class 中起到了承上启下的作用。一方面, abstract class 是抽象的,可以声明抽象方法,以规范子类必须实现的功能;另一方面,它又可以定义缺省的方法体,供子类直接使用或覆盖。另外,它还可以定义自己的实例变量,以供子类通过继承来使用。
    接口中的抽象方法前不用也不能加 abstract 关键字,默认隐式就是抽象方法,也不能加 final 关键字来防止抽象方法的继承。而抽象类中抽象方法前则必须加上 abstract 表示显示声明为抽象方法。
    接口中的抽象方法默认是 public 的,也只能是 public 的,不能用 private , protected 修饰符修饰。而抽象类中的抽象方法则可以用 public , protected 来修饰,但不能用 private 。
    废话一大堆 下边进入正题!
    一、设计原则
    1、找出应用中可能存在变化的部分并独立出来,不要和不变化的代码混在一起;
    2、针对接口编程而不是针对实现编程;
    设计模式-php实现_第1张图片

3、多用组合,少用继承;
4、为了交互对象间松耦合设计努力;
5、类应该对扩展开发,修改关闭,即开发-关闭原则;
6、…

二、策略模式
1、定义:策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
2、模式动机:完成一项任务,往往可以有多种不同的方式,每一种方式称为一个策略,我们可以根据环境或者条件的不同选择不同的策略来完成该项任务。
3、角色分析:
  抽象策略角色:策略类,通常由一个接口或者抽象类实现。
  具体策略角色:包装了相关的算法和行为。
  环境角色:持有一个策略类的引用,最终给客户端调用。
4、代码实现:

strategy = $strategyReflection->newInstance();
        } catch (ReflectionException $e) {
            $this->strategy = "";
        }
    }

    function getLifeStyle()
    {
        $this->strategy->life();
        // var_dump($this->strategy);
    }
}

//测试
$context = new Context();
$context->getStrategy("ManStrategy");
$context->getLifeStyle();
?>

三、观察者模式
1、定义:当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
2、模式动机:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
设计模式-php实现_第2张图片
3、代码实现

_observers = array();
    }

    /**
     * 增加一个新的观察者对象
     * @param Observer $observer
     */
    public function attach(Observer $observer)
    {
        return array_push($this->_observers, $observer);
    }

    /**
     * 删除一个已注册过的观察者对象
     * @param Observer $observer
     */
    public function detach(Observer $observer)
    {
        $index = array_search($observer, $this->_observers);
        if ($index === FALSE || !array_key_exists($index, $this->_observers)) {
            return FALSE;
        }

        unset($this->_observers[$index]);
        return TRUE;
    }

    /**
     * 通知所有注册过的观察者对象
     */
    public function notifyObservers()
    {
        if (!is_array($this->_observers)) {
            return FALSE;
        }

        foreach ($this->_observers as $observer) {
            $observer->update();
        }

        return TRUE;
    }

}

/**
 * 抽象观察者角色
 */
interface Observer
{

    /**
     * 更新方法
     */
    public function update();
}

/**
 * Class ConcreteObserver
 */
class ConcreteObserver implements Observer
{

    /**
     * 观察者的名称
     * @var 
     */
    private $_name;

    public function __construct($name)
    {
        $this->_name = $name;
    }

    /**
     * 更新方法
     */
    public function update()
    {
        echo 'Observer', $this->_name, '已通知成功
'; } } /** * 主题与观察者都使用接口 观察者利用主题接口向主题注册, * 而主题利用观察者接口通知观察者 达到两者不干扰 松耦合 */ //实例化 具体主题角色 类: $subject = new ConcreteSubject(); /* 添加第一个观察者 */ $observer1 = new ConcreteObserver('xiaoming'); $subject->attach($observer1); echo '
第一个通知:
'; $subject->notifyObservers(); /* 添加第二个观察者 */ $observer2 = new ConcreteObserver('xiaoxiao'); $subject->attach($observer2); echo '
第二个通知:
'; $subject->notifyObservers(); /* 删除第一个观察者 */ $subject->detach($observer1); echo '
第三个通知:
'; $subject->notifyObservers();

四、装饰者模式
1、定义:装饰器(Decorator)模式就是对一个已有结构增加"装饰",简单的说就是动态的添加类的功能。(在面向对象的设计中,我们也应该尽量使用对象组合,而不是对象继承来扩展和复用功能。装饰器模式就是基于对象组合的方式,可以实现最大的灵活性 )
2、模式动机:
模式动机:一般有两种方式可以实现给一个类或对象增加行为:
  继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。
  关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator)
装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。
3、代码实现:

component = $component;
    }

    //override
    function operation()
    {
        $this->component->operation();
    }
}

//具体装饰类A
class ConcreteDecoratorA extends Decorator
{
    public function __construct(Component $component)
    {
        parent::__construct($component);

    }

    public function operation()
    {
        parent::operation();
        $this->addedOperationA();   //  新增加的操作
    }

    public function addedOperationA()
    {
        echo ",又加了A个性化装饰
"; } } //具体装饰类B class ConcreteDecoratorB extends Decorator { public function __construct(Component $component) { parent::__construct($component); } public function operation() { parent::operation(); $this->addedOperationB(); // 新增加的操作 } public function addedOperationB() { echo ",又加了B个性化装饰

"; } } //测试 $decoratorA = new ConcreteDecoratorA(new ConcreteComponent()); $decoratorA->operation(); $decoratorB = new ConcreteDecoratorB($decoratorA); $decoratorB->operation(); /* 加了被装饰者,又加了A个性化装饰 加了被装饰者,又加了A个性化装饰 ,又加了B个性化装饰 */

五、工厂模式-》简单工厂
1、定义:工厂模式(Factor Pattern)分为简单工厂、工厂方法、抽象工厂,简单说简单工厂就是负责生成其他对象的类或方法。
2、模式动机:
(a)工厂模式可以将对象的生产从直接new 一个对象,改成通过调用一个工厂方法生产。这样的封装,代码若需修改new的对象时,不需修改多处new语句,只需更改生产对象方法。
(b)若所需实例化的对象可选择来自不同的类,可省略if-else多层判断,给工厂方法传入对应的参数,利用多态性,实例化对应的类。
©问题:如果按照简单工厂模式的话,声明一个工厂类,由工厂类判断调用哪个,那么必然存在工厂类不断修改的操作,每增加一个功能都要去修改工厂类,违背了【开放封闭】原则。
3、图示:

设计模式-php实现_第3张图片
4、代码实现:

makeCar('JeepCar');
$jeepCar->getCar();
echo PHP_EOL;
$sportCar = $car->makeCar('SportCar');
$sportCar->getCar();
echo PHP_EOL;
$zxc = $car->makeCar('自行车');
$zxc->getCar();
echo PHP_EOL;
echo '***********************************************************';

六、工厂模式-》工厂方法
1、介绍:工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。

2、定义:工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。
3、图示:
设计模式-php实现_第4张图片
4、代码实现:

makeCar('JeepCar');
$jeepCar->getCar();
echo PHP_EOL;
$sportCar = $car->makeCar('SportCar');
$sportCar->getCar();
echo PHP_EOL;
$zxc = $car->makeCar('自行车');
$zxc->getCar();
echo PHP_EOL;
echo '***********************简单工厂结束************************************';

echo PHP_EOL;
echo '***********************工厂方法开始************************************';
echo PHP_EOL;
/*
*工厂方法模式:
*定义一个创建对象的接口,让子类决定哪个类实例化。 他可以解决简单工厂模式中的封闭开放原则问题。
*/


interface createCar
{ // 注意了,这里是简单工厂本质区别所在,将对象的创建抽象成一个接口。
    function create();

}

class FactoryJeepCar implements createCar
{
    function create()
    {
        return new JeepCar();
    }
}

class FactorySportCar implements createCar
{
    function create()
    {
        return new SportCar();
    }
}

// 客户端 实现如下:
class Client
{
// 简单工厂里的静态方法
    function test()
    {
        $Factory = new FactoryJeepCar();
        $man = $Factory->create();
        $man->getCar();
        echo PHP_EOL;
        $Factory = new FactorySportCar();
        $man = $Factory->create();
        $man->getCar();
    }
}

$f = new Client;
$f->test();

echo PHP_EOL;
echo '***********************工厂方法结束************************************';

七、工厂模式-》抽象工厂

1、定义:抽象工厂模式为一组相关或相互依赖的对象创建提供接口,而无需指定其具体实现类。抽象工厂的客户端不关心如何创建这些对象,只关心如何将它们组合到一起。
2、抽象工厂的优点/缺点:
优点:
(a)抽象工厂模式隔离了具体类的生产,使得客户并不需要知道什么被创建。
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
(b)增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
缺点:
(a)增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类。

3、代码实现:

makeCar('JeepCar');
$jeepCar->getCar();
echo PHP_EOL;
$sportCar = $car->makeCar('SportCar');
$sportCar->getCar();
echo PHP_EOL;
$zxc = $car->makeCar('自行车');
$zxc->getCar();
echo PHP_EOL;
echo '***********************简单工厂结束************************************';

echo PHP_EOL;
echo '***********************工厂方法开始************************************';
echo PHP_EOL;

/*
*工厂方法模式:
*定义一个创建对象的接口,让子类决定哪个类实例化。 他可以解决简单工厂模式中的封闭开放原则问题。
*/


interface createCar
{ // 注意了,这里是简单工厂本质区别所在,将对象的创建抽象成一个接口。
    function create();

}

class FactoryJeepCar implements createCar
{
    function create()
    {
        return new JeepCar();
    }
}

class FactorySportCar implements createCar
{
    function create()
    {
        return new SportCar();
    }
}

// 客户端 实现如下:
class Client
{
// 简单工厂里的静态方法
    function test()
    {
        $Factory = new FactoryJeepCar();
        $man = $Factory->create();
        $man->getCar();
        echo PHP_EOL;
        $Factory = new FactorySportCar();
        $man = $Factory->create();
        $man->getCar();
    }
}

$f = new Client;
$f->test();

echo PHP_EOL;
echo '***********************工厂方法结束************************************';
echo PHP_EOL;

echo '***********************抽象工厂开始************************************';
echo PHP_EOL;

/*
抽象工厂:提供一个创建一系列相关或相互依赖对象的接口。
注意:这里和工厂方法的区别是:一系列,而工厂方法则是一个。
*/

class JeepCarGreenAbstract implements Car
{
    function getCar()
    {
        echo '我要绿色越野
'; } } class JeepCarBlueAbstract implements Car { function getCar() { echo '我要蓝色越野
'; } } class SportCarGreenAbstract implements Car { function getCar() { echo '我要绿色超跑
'; } } class SportCarBlueAbstract implements Car { function getCar() { echo '我要蓝色超跑
'; } } interface createCarAbstract { // 注意了,这里是本质区别所在,将对象的创建抽象成一个接口。 function createBlueCar(); function createGreenCar(); } class FactoryJeepCarAbstract implements createCarAbstract { function createBlueCar() { return new JeepCarBlueAbstract(); } function createGreenCar() { return new JeepCarGreenAbstract(); } } class FactorySportCarAbstract implements createCarAbstract { function createBlueCar() { return new SportCarBlueAbstract(); } function createGreenCar() { return new SportCarGreenAbstract(); } } class ClientAbstractFactory { // 简单工厂里的静态方法 function test() { $Factory = new FactorySportCarAbstract(); $sportCar = $Factory->createBlueCar(); echo PHP_EOL; $sportCar->getCar(); echo PHP_EOL; $sportCar = $Factory->createGreenCar(); $sportCar->getCar(); echo PHP_EOL; $Factory = new FactoryJeepCarAbstract(); $jeepCar = $Factory->createBlueCar(); $jeepCar->getCar(); echo PHP_EOL; $jeepCar = $Factory->createGreenCar(); $jeepCar->getCar(); echo PHP_EOL; } } $f = new ClientAbstractFactory; $f->test(); echo '***********************抽象工厂结束************************************'; echo PHP_EOL;

八、工厂模式 总结
1、区别:
(a)简单工厂模式:用来生产同一等级结构中的任意产品。对与增加新的产品,无能为力
(b)工厂模式 :用来生产同一等级结构中的固定产品。(支持增加任意产品)
©抽象工厂 :用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
以上三种工厂 方法在等级结构和产品族这两个方向上的支持程度不同。所以要根据情况考虑应该使用哪种方法。

2、适用范围:

(a)简单工厂模式:工厂类负责创建的对象较少,客户只知道传入工厂类的参数,对于如何创建对象不关心。
(b)工厂方法模式:当一个类不知道它所必须创建对象的类或一个类希望由子类来指定它所创建的对象时,当类将创建对象的职责委托给多个帮助子类中得某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候,可以使用工厂方法模式。
©抽象工厂模式:一个系统不应当依赖于产品类实例何如被创建,组合和表达的细节,这对于所有形态的工厂模式都是重要的。这个系统有多于一个的产品族,而系统只消费其 中某一产品族。同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。系统提供一个产品类的库,所有的产品以同样的接口出现,从 而使客户端不依赖于实现。
4、无论是简单工厂模式、工厂模式还是抽象工厂模式,它们本质上都是将不变的部分提取出来,将可变的部分留作接口,以达到最大程度上的复用。究竟用哪种设计模式更适合,这要根据具体的业务需求来决定。

九、其他模式(未完待续)

你可能感兴趣的:(设计模式)