php面向对象编程6大原则+3大类型+9大设计模式

做学习记录使用

一、面向对象编程的6大设计原则(单里依接最开)

单一职责原则——类要职责单一,一个类只需要做好一件事情。
里氏替换原则——子类可以扩展父类的功能,但不能改变父类原有的功能(可以实现父类的抽象方法和增加自己特有的方法,不要覆盖父类的非抽象方法)。
依赖倒置原则——-面向接口编程:只需关心接口,不需要关心实现。  
接口隔离原则——-建立单一接口,尽量细化接口,接口中的方法尽量少。低耦合高内聚。
最少知识原则——-一个类对自己依赖的类知道的越少越好,两实体间最好不交互或少交互。
开闭原则——-对扩展开放,对修改关闭。


二、设计模式3大类型(创建型、结构型、行为型)

按作用可分为3大类:创建型、结构型、行为型。按范围可分为2大类:类、对象
创建型模式(单例+工厂):就是用来创建对象的模式。
结构型模式(外观+装饰器+适配器):采用继承来组合接口或实现,描述了组合对象来建立新功能的方法。
行为型模式(策略+观察者):核心是算法和对象之间职责的分配,描述了对象或类的模式和之间的通信模式,大多设计模式都是对象模式。
类模式:重点在于类及其子类之间的关系,类范围中包含四种模式,类模式是静态的。
对象模式:强调的是可以在运行时改变的对象,因此这些写模式更具动态性。大多设计模式都是对象模式。

设计模式主要分三大类型:创建型、结构型和行为型。
创建型:
(1)Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点
(2)Abstract Factory,抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。
(3)Factory Method,工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。
(4)Builder,建造模式:将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。
(5)Prototype,原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。
结构型有:
(1)Composite,组合模式:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。
(2)Facade,外观模式:为子系统中的一组接口提供一致的界面,fa?ade提供了一高层接口,这个接口使得子系统更容易使用。
(3)Proxy,代理模式:为其他对象提供一种代理以控制对这个对象的访问
(4)Adapter,适配器模式:将一类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些类可以一起工作。
(5)Decrator,装饰模式:动态地给一个对象增加一些额外的职责,就增加的功能来说,Decorator模式相比生成子类更加灵活。
(6)Bridge,桥模式:将抽象部分与它的实现部分相分离,使他们可以独立的变化。
(7)Flyweight,享元模式
行为型:
(1)Iterator,迭代器模式:提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。
(2)Observer,观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。
(3)Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。
(4)Command,命令模式:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。
(5)State,状态模式:允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。
(6)Strategy,策略模式:定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。
(7)China of Responsibility,职责链模式:使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系
(8)Mediator,中介者模式:用一个中介对象封装一些列的对象交互。
(9)Visitor,访问者模式:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这个元素的新操作。
(10)Interpreter,解释器模式:给定一个语言,定义他的文法的一个表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
(11)Memento,备忘录模式:在不破坏对象的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
 


三、9大设计模式和应用场景

9大设计模式:单例、工厂、观察者、适配器、策略、装饰器

单例:单例设计模式常应用于数据库类设计,采用单例模式,只连接一次数据库,防止打开多个数据库连接。

策略:将一组特定的行为和算法封装成类,以适应某些特定的上下文环境。例如:一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有广告位展示不同的广告

适配器:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。例如:php连接数据库的方法:mysql,,mysqli,pdo,可以用适配器统一

工厂:常用于根据输入参数的不同或者应用程序配置的不同来创建一种专门用来实例化并返回其对应的类的实例。 

观察者:一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;观察者模式为您提供了避免组件之间紧密耦。

装饰器:动态地添加修改类的功能。

门面模式(外观模式):一个接口统一调用多个系统的接口。屏蔽子系统组件,实现子系统与客户间的松耦合。

注册模式:解决全局共享和交换对象

原型模式:大对象的创建,对象克隆以避免创建对象时的消耗

注意:单例模式和3种工厂模式都是通过静态方法来操作的


四、具体讲解与代码

单例:单例设计模式常应用于数据库类设计,采用单例模式,只连接一次数据库,防止打开多个数据库连接。

利用$_instance私有变量来保存类的唯一实例化对象;
设计一个getInstance对外公开的静态函数,可以获取类唯一实例;
防止用户用new实例化和克隆,构造两个__construct、__clone私有函数;

<?php  
    
/** 
* 单例模式
*/  
class Database  
{  
  // We need a static private variable to store a Database instance.  
  private static $instance;  
    
  // Mark as private to prevent it from being instanced.  
  private function __construct()  
  {  
    // Do nothing.  
  }  
    
  private function __clone()   
  {  
    // Do nothing.  
  }  
    
  public static function getInstance()   
  {  
    if (!(self::$instance instanceof self)) {  
      self::$instance = new self();  
    }  
    
    return self::$instance;  
  }  
}  
    
$a =Database::getInstance();  
$b =Database::getInstance();  
    
// true  
var_dump($a === $b);  

策略:多个类只区别在表现行为不同,需要在不同情况下使用不同的策略,实现需要知道所有的策略类,对用户隐藏具体策略的实现细节。比如电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有的广告位展示不同的广告。
2种注入策略对象的方式:construct注册和方法注册

// contruct注册策略对象
interface Love
{
	function sajiao();
}
 
class KeAi implements Love
{
	function sajiao()
	{
		echo "讨厌<br>";
	}
}
 
class Tiger implements Love
{
		function sajiao()
	{
		echo "给老娘过来<br>";
	}
}
 
class strategy
{
	protected $_obj;
	public function __construct(Love $obj)
	{
		$this->_obj = $obj;
	}
	public function sajiao()
	{
		return $this->_obj->sajiao();
	}
}
 
// 测试
$strategy = new strategy(new KeAi());
$strategy->sajiao();//"讨厌<br>"
$strategy = new strategy(new Tiger());
$strategy->sajiao();//"给老娘过来<br>"
//方法注册策略对象
interface clothesAction{  
    public function display();  
}  
   
class ShowBoyClothes implements clothesAction{  
    public function display(){  
        echo "There are many boy clothes<br>";  
    }  
}  
   
class ShowGirlClothes implements clothesAction{  
    public function display(){  
        echo "There are many girl clothes<br>";  
    }  
}  
class strategy{  
    protected $_obj;  
    public function setClothes(clothesAction $clothes){  
        $this->_obj = $clothes;  
    }  
    public function showClothes(){  
        $this->_obj->display();  
    }  
}  
   
// 测试 
$strategy = new strategy();   
$strategy->setClothes(new ShowBoyClothes());  
$strategy->showClothes();//"There are many boy clothes<br>"               
$strategy->setClothes(new ShowGirlClothes()); 
$strategy->showClothes();//echo "There are many girl clothes<br>";   

适配器:

(1)将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。

(2)老代码接口不适应新的接口需求,又因为代码很多很乱不继续修改,需要适配器兼容老接口的同时,扩充新功能。

(3)可将不同的接口适配成统一的接口(策略模式)。例如:php连接数据库的方法:mysql,mysqli,pdo,可以用适配器统一。

// 实例1:
//适配器模式问题的始末详见:https://www.cnblogs.com/DeanChopper/p/4770572.html
//1、源
abstract class Toy  
{  
    public abstract function openMouth();  
  
    public abstract function closeMouth();  
}  
  
class Dog extends Toy  
{  
    public function openMouth()  
    {  
        echo "Dog open Mouth<br>";  
    }  
  
    public function closeMouth()  
    {  
        echo "Dog close Mouth<br>";  
    }  
}  
  
class Cat extends Toy  
{  
    public function openMouth()  
    {  
        echo "Cat open Mouth<br>";  
    }  
  
    public function closeMouth()  
    {  
        echo "Cat close Mouth<br>";  
    }  
} 
 
 
 
//2、目标角色:红枣遥控公司+绿枣遥控公司  
interface RedTarget  
{  
    public function doMouthOpen();  
    public function doMouthClose();  
}  
 
interface GreenTarget  
{  
    public function operateMouth($type = 0);  
} 
 
 
//3、适配器代码:红枣遥控公司+绿枣遥控公司  
class RedAdapter implements RedTarget  
{  
    private $adaptee;   
    function __construct(Toy $adaptee)  
    {  
        $this->adaptee = $adaptee;  
    }  
 
    public function doMouthOpen()  
    {  
        $this->adaptee->openMouth();  
    }  
  
    public function doMouthClose()  
    {  
        $this->adaptee->closeMouth();  
    }  
}  
 
class GreenAdapter implements GreenTarget  
{  
    private $adaptee;  
  
    function __construct(Toy $adaptee)  
    {  
        $this->adaptee = $adaptee;  
    }  
 
    public function operateMouth($type = 0)  
    {  
        if ($type) {  
            $this->adaptee->openMouth();  
        } else {  
            $this->adaptee->closeMouth();  
        }  
    }  
}
 
//4、测试用例
class testDriver  
{  
    public function run()  
    {  
         //实例化一只狗玩具  
        $adaptee_dog = new Dog();  
        echo "给狗套上红枣适配器<br>";  
        $adapter_red = new RedAdapter($adaptee_dog);  
        //张嘴  
        $adapter_red->doMouthOpen();  
        //闭嘴  
        $adapter_red->doMouthClose();  
        echo "给狗套上绿枣适配器<br>";  
        $adapter_green = new GreenAdapter($adaptee_dog);  
        //张嘴  
        $adapter_green->operateMouth(1);  
        //闭嘴  
        $adapter_green->operateMouth(0);  
    }  
}  
  
$test = new testDriver();  
$test->run(); 
//结果:
// 给狗套上红枣适配器
// Dog open Mouth
// Dog close Mouth
// 给狗套上绿枣适配器
// Dog open Mouth
// Dog close Mouth
//实例2:wife类的内容要扩充,但是又不能直接改
// 详见:https://www.php.cn/code/20267.html
interface PerfectPeople
{
	function cook();
	function writePhp();
}
 
class Wife
{
	fucntion cook()
	{
		echo "我会做满汉全席<br>";
	}
}
 
class adapter
{
	protected $_obj;
	public function __construct($obj)
	{
		$this->_obj = $obj;
	}
	public function cook()
	{
		return $this->_obj->cook();
	}
 
	public fucntion writePhp()
	{
		echo "我会写php代码<br>";
	}
}
 
// 测试
$adapter = new adapter(new Wife());
$adapter->cook();// "我会做满汉全席<br>"
$adapter->writePhp();// "我会写php代码<br>"
// 实例3:多个数据库连接实例
interface IDatabase
{
    function connect($host, $user, $passwd, $dbname);
    function query($sql);
    function close();
}
 
class MySQL implements IDatabase
{
    protected $conn;
    function connect($host, $user, $passwd, $dbname)
    {
        $conn = mysql_connect($host, $user, $passwd);
        mysql_select_db($dbname, $conn);
        $this->conn = $conn;
    }
 
    function query($sql)
    {
        $res = mysql_query($sql, $this->conn);
        return $res;
    }
 
    function close()
    {
        mysql_close($this->conn);
    }
}
 
class MySQLi implements IDatabase
{
    protected $conn;
 
    function connect($host, $user, $passwd, $dbname)
    {
        $conn = mysqli_connect($host, $user, $passwd, $dbname);
        $this->conn = $conn;
    }
 
    function query($sql)
    {
        return mysqli_query($this->conn, $sql);
    }
 
    function close()
    {
        mysqli_close($this->conn);
    }
}
 
class PDO implements IDatabase
{
    protected $conn;
    function connect($host, $user, $passwd, $dbname)
    {
        $conn = new \PDO("mysql:host=$host;dbname=$dbname", $user, $passwd);
        $this->conn = $conn;
    }
function query($sql)
    {
        return $this->conn->query($sql);
    }
 
    function close()
    {
        unset($this->conn);
    }
}
// 数据库适配器
class DatabaseAdapter
{
	protected $_obj;
	public function __construct($obj)
	{
		$this->_obj = $obj;
		return $this->_obj;
	}
    function connect($host, $user, $passwd, $dbname)
    {
		$this->_obj->connect();
    }
    function query($sql)
    {
		$this->_obj->query();
    }
    function close()
    {
		$this->_obj->close();
    }
}
// 测试
$mysql = new DatabaseAdapter(new MySQL());
$mysql->query('select * from tabname where id=1');

策略模式&适配器模式:策略模式都是适配器模式,反之不成立,简言之,适配器模式包括策略模式,适配器模式范围大。

工厂模式
https://www.cnblogs.com/aqsmoke/p/3955310.html
工厂模式的几种形态:
1、简单工厂模式(Simple Factory),又叫做  静态工厂方法模式(Static Factory Method)

2、工厂方法模式(Factory Method), 又叫做  多态性工厂模式(Polymorphic Factory)

3、抽象工厂模式(Abstract Factory), 又叫做 工具箱模式(ToolKit)

简单工厂模式:通过工厂类的静态方法来创建对象。

// 案例1: https://www.php.cn/code/20265.html 视频解析
// interface  people {
//     function  jiehun();
// }
// class man implements people{
//     function jiehun() {
//         echo '送戒指<hr>';
//     }
// }
 
// class women implements people {
//     function jiehun() {
//         echo '穿婚纱<hr>';
//     }
// }
 
// class SimpleFactoty {
//     // 简单工厂里的静态方法
//     public static function create_obj($type)
//     {
//         switch($type)
//         {
//             case 'man':
//                 $obj =  new man();
//                 break;
//             case 'women':
//                 $obj = new women();
//                 break;
//         }
//         return $obj;
//     } 
// }
 
// $person1 = SimpleFactoty::create_obj('man');
// $person1->jiehun();//"送戒指<hr>"
// $person2 = SimpleFactoty::create_obj('women');
// $person2->jiehun();//"穿婚纱<hr>"
 
//=====其中man类变为superman('a','b')
interface  people {
    function  jiehun();
}
class superman implements people{
    protected $_a;
    protected $_b;
    public function __construct($a,$b)
    {
        $this->_a = $a;
        $this->_b = $b;
    }
    function jiehun() {
        echo $this->_a.'、'.$this->_b.'送戒指<hr>';
    }
}
 
class women implements people {
    function jiehun() {
        echo '穿婚纱<hr>';
    }
}
 
class SimpleFactoty {
    // 简单工厂里的静态方法
    public static function create_obj($type)
    {
        switch($type)
        {
            case 'man':
                $obj =  new superman('手捧鲜花','单膝跪地');
                break;
            case 'women':
                $obj = new women();
                break;
        }
        return $obj;
    } 
}
 
$person1 = SimpleFactoty::create_obj('man');
$person1->jiehun();//"手捧鲜花、单膝跪地送戒指<hr>"
$person2 = SimpleFactoty::create_obj('women');
$person2->jiehun();//"穿婚纱<hr>"
// 案例2
interface InterfaceShape 
{
 function getArea();
 function getCircumference();
}
  
/**
* 矩形  
*/
class Rectangle implements InterfaceShape
{
  private $width;
  private $height;
   
  public function __construct($width, $height)
  {
    $this->width = $width;
    $this->height = $height;
  }
  
  public function getArea() 
  {
    return $this->width* $this->height;
  }
  
  public function getCircumference()
  {
    return 2 * $this->width + 2 * $this->height;
  }
}
  
/**
* 圆形
*/
class Circle implements InterfaceShape
{
  private $radius;
  
  function __construct($radius)
  {
    $this->radius = $radius;
  }
  
  
  public function getArea() 
  {
    return M_PI * pow($this->radius, 2);
  }
  
  public function getCircumference()
  {
    return 2 * M_PI * $this->radius;
  }
}
  
/**
* 形状工厂类
*/
class FactoryShape 
{ 
  public static function create()
  {
    switch (func_num_args()) {
      case 1: return new Circle(func_get_arg(0));break;
      case 2: return new Rectangle(func_get_arg(0), func_get_arg(1));break;
      default: break;
    }
  } 
}
  
$rect =FactoryShape::create(5,5);
// object(Rectangle)#1 (2) { ["width":"Rectangle":private]=> int(5) ["height":"Rectangle":private]=> int(5) }
var_dump($rect);
echo "<br>";
  
// object(Circle)#2 (1) { ["radius":"Circle":private]=> int(4) }
$circle =FactoryShape::create(4);
var_dump($circle);

工厂方法模式:使一个类的实例化延迟到其子类。工厂只负责规定接口(父:工厂接口),具体对象的创建交给子类工厂(子:工厂类),但是创建还是在静态方法中创建的。
与简单工厂模式的区别:将对象的创建抽象成一个接口。
https://www.cnblogs.com/wilburxu/p/6086394.html
使用场景
1、支付宝、微信、银联的连接方式(connectMode),支付方式(payMode)。   使用工厂模式,“客户”就不需要不要知道具体的连接方式和支付方式了, 只需要调用connectMode 和payMode即可。 
2、MySQL、SQL Server、Oracle等数据库的连接方式(connectMode)、查询方式(selectMode)等操作可以使用工厂模式进行封装。下面的例子会讲到。
https://www.cnblogs.com/mingaixin/p/4324156.html 
https://www.cnblogs.com/houdabao/p/9525392.html  支付宝、微信、银联

interface  people {
    function  jiehun();
}
class man implements people{
    function jiehun() {
        echo '送戒指';
    }
}
class women implements people {
    function jiehun() {
        echo '穿婚纱';
    }
}
interface  createObj {  //注意了,这里是简单工厂本质区别所在,将对象的创建抽象成一个接口。
    function create();
 
}
class FactoryMan implements createObj {
    function create() {
        return  new man;
    }
}
class FactoryWomen implements createObj {
    function create() {
        return new women;
    }
}
 
class  Client {
    // 工厂方法
    function test() {
        $Factory =  new  FactoryMan;
        $man = $Factory->create();
        $man->jiehun();
        
        $Factory =  new  FactoryWomen;
        $man = $Factory->create();
        $man->jiehun();
    }
}
 
$f = new Client;
$f->test();//送戒指 穿婚纱

抽象工厂模式: 与工厂方法的区别:一系列,而工厂方法则是一个。

interface  people {
    function  jiehun();
}
class Oman implements people{
    function jiehun() {
        echo '美女,我送你玫瑰和戒指!<br>';
    }
}
class Iman implements people{
    function jiehun() {
        echo '我偷偷喜欢你<br>';
    }
}
  
class Owomen implements people {
    function jiehun() {
        echo '我要穿婚纱!<br>';
    }
}
  
class Iwomen implements people {
    function jiehun() {
        echo '我好害羞哦!!<br>';
    }
}
  
interface  createMan {
    function createOpen(); //外向的
    function createIntro(); //内向
  
}
class FactoryMan implements createMan{
    function createOpen() {
        return  new  Oman;
    }
    function createIntro() {
        return  new Iman;
    }
}
class FactoryWomen implements createMan {
    function createOpen() {
        return  new  Owomen;
    }
    function createIntro() {
        return  new Iwomen;
    }
}
  
class  Client {
    // 简单工厂里的静态方法
    function test() {
        $Factory =  new  FactoryMan;
        $man = $Factory->createOpen();
        $man->jiehun();
         
        $man = $Factory->createIntro();
        $man->jiehun();
         
         
        $Factory =  new  FactoryWomen;
        $man = $Factory->createOpen();
        $man->jiehun();
         
        $man = $Factory->createIntro();
        $man->jiehun();
         
    }
}
  
$f = new Client;
$f->test();

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

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

观察者:一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;观察者模式为您提供了避免组件之间紧密耦。

//视频链接:https://www.php.cn/code/20266.html
class Man
{
    // 用来存放观察者
    protected $observers = [];
    public function addObserver($observer)
    {
        $this->observers[] = $observer;
    }
    public function delObserver($observer)
    {
        $key = array_search($observer, $this->observers);//查找key
        array_splice($this->observers, $key, 1);//替换函数进行删除
    }
    //当被观察者做出这个行为,通知观察者做出反应
    public function buy() 
    {
        foreach ($this->observers as $girl) {
            $girl->dongjie();
        }
    }
}
 
class GirlFriend
{
    public function dongjie()
    {
        echo '冻结他的银行卡<hr>';
    }
}
 
// 测试
//step1:创建被观察者和观察者对象
$xiaoming = new Man();
$xiaomei = new GirlFriend();
$xiaohua = new  GirlFriend();
//step2:添加观察者
$xiaoming->addObserver($xiaomei);
$xiaoming->addObserver($xiaohua);
//step3:触发事件
$xiaoming->buy();// "冻结他的银行卡<hr>"  "冻结他的银行卡<hr>"
//step4:删除一个观察者
$xiaoming->delObserver($xiaomei); 
//step5:触发事件
$xiaoming->buy();// "冻结他的银行卡<hr>"
<?php
//==================被观察者,start==================//
// addObserver($observer)
// removeObserver($observer_name)
// addListener($listener)
 
// 可被观察者接口
interface InterfaceObservable{
  function addObserver($observer);
  function removeObserver($observer_name);
}
 
// 可被观察者抽象类
abstract class Observable implements InterfaceObservable{
  protected $observers = array();
  
  public function addObserver($observer){
    if ($observer instanceof InterfaceObserver){
      $this->observers[] = $observer;
    }
  }
  
  public function removeObserver($observer_name) {
    foreach ($this->observers as $index => $observer) {
      if ($observer->getObserverName() === $observer_name) {
        array_splice($this->observers, $index, 1);
        return;
      }
    }
  }
}
 
// 模拟一个可以被观察的类
class A extends Observable {
  public function addListener($listener){
    foreach ($this->observers as $observer)  {
      $observer->onListen($this, $listener);
    }
  }
}
//==================被观察者,end==================//
 
 
 
 
//==================观察者,start==================//
// protected $observer_name
// getObserverName()
// onListen($sender, $args) //$sender被观察者对象,$args被观察内容
 
// 观察者接口
interface InterfaceObserver{
  function onListen($sender, $args);
  function getObserverName();
}
 
// 观察者抽象类
abstract class Observer implements InterfaceObserver{
  protected $observer_name;
  
  function getObserverName(){
    return $this->observer_name;
  }
  
  function onListen($sender, $args){}
}
 
// 模拟一个观察者类
class B extends Observer 
{
  protected $observer_name = 'B';
  
  public function onListen($sender, $args) 
  {
    var_dump($sender);
    echo "<br>";
    var_dump($args);
    echo "<br><hr>";
  }
}
  
// 模拟另外一个观察者类
class C extends Observer 
{
  protected $observer_name = 'C';
  
  public function onListen($sender, $args) 
  {
    var_dump($sender);
    echo "<br>";
    var_dump($args);
    echo "<br><hr>";
  }
}
//==================观察者,end==================//
 
 
$a = new A();
// 注入观察者
$a->addObserver(new B());
$a->addObserver(new C()); 
// 可以看到观察到的信息
$a->addListener('D');//A对象(B,C对象在其数组中),D
  
// 移除观察者
$a->removeObserver('B');
// 可以看到观察到的信息
$a->addListener('D');//object(B,C对象在其数组中),D
 
 
/*
object(A)#1 (1) { ["observers":protected]=> array(2) { 
	[0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } 
	[1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } 
}
string(1) "D"
object(A)#1 (1) { ["observers":protected]=> array(2) { 
	[0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } 
	[1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } 
}
string(1) "D"
*/
 
/*
object(A)#1 (1) { ["observers":protected]=> array(1) { 
	[0]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } 
}
string(1) "D"
*/

装饰器
1:装饰器模式,可以动态的添加修改类的功能 
2:一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重写实现类的方法 
3:使用装饰器模式,仅需要在运行时添加一个装饰器对象即可实现,可以实现最大额灵活性。

/* https://www.imooc.com/article/17108
如果有一个游戏角色,他原来就是默认穿一件长衫。现在游戏改进了,觉得这个角色,除了穿一件长衫前,还可以在里面穿一件袍子,或是一件球衣。在外面穿一套盔甲或是宇航服。*/
 
/*游戏原来的角色类
class Person{
    public function clothes(){
        echo "长衫".PHP_EOL;
    }
}
*/
 
//装饰器接口
interface Decorator
{
   public function beforeDraw();
   public function afterDraw();
}
//具体装饰器1-宇航员装饰
class AstronautDecorator implements Decorator
{
    public function beforeDraw()
    {
        echo "穿上T恤".PHP_EOL;
    }
    function afterDraw()
    {
        echo "穿上宇航服".PHP_EOL;
        echo "穿戴完毕".PHP_EOL;
    }
}
//具体装饰器2-警察装饰
class PoliceDecorator implements Decorator{
    public function beforeDraw()
    {
        echo "穿上警服".PHP_EOL;
    }
    function afterDraw()
    {
        echo "穿上防弹衣".PHP_EOL;
        echo "穿戴完毕".PHP_EOL;
    }
}
//被装饰者
class Person{
    protected $decorators = array(); //存放装饰器
    //添加装饰器
    public function addDecorator(Decorator $decorator)
    {
        $this->decorators[] = $decorator;
    }
    //所有装饰器的穿长衫前方法调用
    public function beforeDraw()
    {
        foreach($this->decorators as $decorator)
        {
            $decorator->beforeDraw();
        }
    }
    //所有装饰器的穿长衫后方法调用
    public function afterDraw()
    {
        $decorators = array_reverse($this->decorators);
        foreach($decorators as $decorator)
        {
            $decorator->afterDraw();
        }
    }
    //装饰方法
    public function clothes(){
        $this->beforeDraw();
        echo "穿上长衫".PHP_EOL;
        $this->afterDraw();
    }
}
//警察装饰
$police = new Person;
$police->addDecorator(new PoliceDecorator);
$police->clothes();
//宇航员装饰
$astronaut = new Person;
$astronaut->addDecorator(new AstronautDecorator);
$astronaut->clothes();
//混搭风
$madman = new Person;
$madman->addDecorator(new PoliceDecorator);
$madman->addDecorator(new AstronautDecorator);
$madman->clothes();
<?php
  
/*
装饰器模式
*/
interface Decorator{
  public function display();
}
 
 
class XiaoFang implements Decorator{
  private $name;
  public function __construct($name){
      $this->name = $name; 
  }
  public function display(){
      echo "我是".$this->name.",我出门了!!!"."<br>"; 
  }
}
 
 
class Finery implements Decorator{
  private $component;
  public function __construct(Decorator $component){
      $this->component=$component; 
  }
  public function display(){
      $this->component->display(); 
  }
}
 
 
class Shoes extends Finery{
  public function display(){
    echo "穿上鞋子"."<br>";
    parent::display();
  }
}
 
 
class Skirt extends Finery{
  public function display(){
    echo "穿上裙子"."<br>";
    parent::display();
  }
}
 
class Fire extends Finery{
  public function display(){
    echo "出门前先整理头发"."<br>";
    parent::display();
    echo "出门后再整理一下头发"."<br>";
  }
}
 
$xiaofang=new XiaoFang("小芳");
$shoes=new Shoes($xiaofang);
$skirt=new Skirt($shoes);
$fire=new Fire($skirt);
$fire->display();
// 输出结果:
// 出门前先整理头发
// 穿上裙子
// 穿上鞋子
// 我是小芳,我出门了!!!
// 出门后再整理一下头发

门面模式(外观模式):一个接口统一调用多个系统的接口。屏蔽子系统组件,实现子系统与客户间的松耦合。
适用场景:
1、为一些复杂的子系统提供一组接口
2、提高子系统的独立性
3、在层次化的结构中国呢,可以使用门面方式定义系统的每一层的接口。

//拍照为例:
//拍: 打开闪光灯->打开照相机,
//不拍:关闭闪光灯->关闭照相机
// class Light
// {
//     public function turnOn()
//     {
//         echo '打开闪光灯<hr>';
//     }
//         public function turnOff()
//     {
//         echo '关闭闪光灯<hr>';
//     }
// }
 
// class Camera
// {
//     public function active()
//     {
//         echo '打开照相机<hr>';
//     }
//         public function deactive()
//     {
//         echo '关闭照相机<hr>';
//     }
// }
// //原有的调用:
// $Light = new Light();
// $Light->turnOn();// "打开闪光灯<hr>" 
// $Camera = new Camera();
// $Camera->active();// "打开照相机<hr>"
//====门面模式
class Light
{
    public function turnOn()
    {
        echo '打开闪光灯<hr>';
    }
        public function turnOff()
    {
        echo '关闭闪光灯<hr>';
    }
}
 
class Camera
{
    public function active()
    {
        echo '打开照相机<hr>';
    }
        public function deactive()
    {
        echo '关闭照相机<hr>';
    }
}
 
class Facade
{
    protected $light;
    protected $camera;
    public function __construct()
    {
        $this->light = new Light();
        $this->camera = new Camera();
    }
    public function start()
    {
        $this->light->turnOn();
        $this->camera->active();
    }
    public function stop()
    {
        $this->light->turnOff(); 
        $this->camera->deactive();
    }
}
//门面模式包装后的调用
$Facade = new Facade();
$Facade->start();// "打开闪光灯<hr>" "打开照相机<hr>"

注册模式
注册模式,解决全局共享和交换对象。已经创建好的对象,挂在到某个全局可以使用的数组上,在需要使用的时候,直接从该数组上获取即可。将对象注册到全局的树上。任何地方直接去访问。

class Register
{
    protected static  $objects;
    function set($alias,$object)//将对象注册到全局的树上
    {
        self::$objects[$alias]=$object;//将对象放到树上
    }
    static function get($name){
        return self::$objects[$name];//获取某个注册到树上的对象
    }
    function _unset($alias)
    {
        unset(self::$objects[$alias]);//移除某个注册到树上的对象。
    }
}

 原型模式(对象克隆以避免创建对象时的消耗) 
1:与工厂模式类似,都是用来创建对象。 
2:与工厂模式的实现不同,原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。这样就免去了类创建时重复的初始化操作。 
3:原型模式适用于大对象的创建,创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需要内存拷贝即可。

Canvas.php
<?php
require_once 'Loader.php';
class Canvas{
private $data;
function init($width = 20, $height = 10)
    {
        $data = array();
        for($i = 0; $i < $height; $i++)
        {
            for($j = 0; $j < $width; $j++)
            {
                $data[$i][$j] = '*';
            }
        }
        $this->data = $data;
    }
function rect($x1, $y1, $x2, $y2)
    {
        foreach($this->data as $k1 => $line)
        {
            if ($x1 > $k1 or $x2 < $k1) continue;
           foreach($line as $k2 => $char)
            {
              if ($y1>$k2 or $y2<$k2) continue;
                $this->data[$k1][$k2] = '#';
            }
        }
    }
 
    function draw(){
        foreach ($this->data as $line){
            foreach ($line as $char){
                echo $char;
            }
            echo "<br>;";
        }
    }
}
 
 
 
Index.php
<?php
require 'Loader.php';
$c = new Canvas();
$c->init();
/ $canvas1 = new Canvas();
// $canvas1->init();
$canvas1 = clone $c;//通过克隆,可以省去init()方法,这个方法循环两百次
//去产生一个数组。当项目中需要产生很多的这样的对象时,就会new很多的对象,那样
//是非常消耗性能的。
$canvas1->rect(2, 2, 8, 8);
$canvas1->draw();
echo "-----------------------------------------<br>";
// $canvas2 = new Canvas();
// $canvas2->init();
$canvas2 = clone $c;
$canvas2->rect(1, 4, 8, 8);
$canvas2->draw();

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值