设计模式的作用:一方面将变化的东西封装起来,另一方面将众多的类抽象开防止类过多
1、简单工厂模式
不同条件下创建不同实例
2、抽象工厂模式
简单工厂模式有个问题,每添加一次新的类都要修改方法,不符合面向对象的开闭原则(对类的增加开放,对类的修改闭合)
抽象工厂模式便解决了这一问题,每次添加新的类就行了。
3、单例模式
保证一个类仅有一个实例
<?php namespace Test; class Database { //私有化内部实例化的对象 private static $instance = null; //私有化构造方法,禁止外部实例化 private function __construct(){} //私有化__clone,防止被克隆 private function __clone(){} // 公有静态实例方法 public static function getInstance(){ if(empty(self::$instance)){ self::$instance=new Test(); } return self::$instance; } } $obj1=Test::getInstance(); $obj2=Test::getInstance(); echo $obj1==$obj2?1:0;
4、观察者模式
一对多的依赖关系,在观察目标类里有一个 ArrayList 存放观察者们。当观察目标对象的状态发生改变,所有依赖于它的观察者都将得到通知,使这些观察者能够自动更新(即使用推送方式)
主题提供注册和通知的接口,观察者提供自身操作的接口。(这些观察者拥有一个同一个接口。)观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者。耦合度相当之低。
如何实现观察者注册?通过前面的注册者模式很容易给我们提供思路,把这些对象加到一棵注册树上就好了嘛。如何通知?这就更简单了,对注册树进行遍历,让每个对象实现其接口提供的操作。
<?php // 主题接口 interface Subject{ public function register(Observer $observer); public function notify(); } // 观察者接口 interface Observer{ public function watch(); } // 主题 class Action implements Subject{ public $_observers=array(); public function register(Observer $observer){ $this->_observers[]=$observer; } public function notify(){ foreach ($this->_observers as $observer) { $observer->watch(); } } } // 观察者 class Cat implements Observer{ public function watch(){ echo "Cat watches TV<hr/>"; } } class Dog implements Observer{ public function watch(){ echo "Dog watches TV<hr/>"; } } class People implements Observer{ public function watch(){ echo "People watches TV<hr/>"; } } // 应用实例 $action=new Action(); $action->register(new Cat()); $action->register(new People()); $action->register(new Dog()); $action->notify();
5、责任链模式
拦截的类都实现统一接口,每个接收者都包含对下一个接收者的引用。将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
<?php //申请Model class Request { //数量 public $num; //申请类型 public $requestType; //申请内容 public $requestContent; } //抽象管理者 abstract class Manager { protected $name; //管理者上级 protected $manager; public function __construct($_name) { $this->name = $_name; } //设置管理者上级 public function SetHeader(Manager $_mana) { $this->manager = $_mana; } //申请请求 abstract public function Apply(Request $_req); } //经理 class CommonManager extends Manager { public function __construct($_name) { parent::__construct($_name); } public function Apply(Request $_req) { if($_req->requestType=="请假" && $_req->num<=2) { echo "{$this->name}:{$_req->requestContent} 数量{$_req->num}被批准。<br/>"; } else { if(isset($this->manager)) { $this->manager->Apply($_req); } } } } //总监 class MajorDomo extends Manager { public function __construct($_name) { parent::__construct($_name); } public function Apply(Request $_req) { if ($_req->requestType == "请假" && $_req->num <= 5) { echo "{$this->name}:{$_req->requestContent} 数量{$_req->num}被批准。<br/>"; } else { if (isset($this->manager)) { $this->manager->Apply($_req); } } } } //总经理 class GeneralManager extends Manager { public function __construct($_name) { parent::__construct($_name); } public function Apply(Request $_req) { if ($_req->requestType == "请假") { echo "{$this->name}:{$_req->requestContent} 数量{$_req->num}被批准。<br/>"; } else if($_req->requestType=="加薪" && $_req->num <= 500) { echo "{$this->name}:{$_req->requestContent} 数量{$_req->num}被批准。<br/>"; } else if($_req->requestType=="加薪" && $_req->num>500) { echo "{$this->name}:{$_req->requestContent} 数量{$_req->num}再说吧。<br/>"; } } }
调用:
header("Content-Type:text/html;charset=utf-8"); //--------------------职责链模式---------------------- require_once "./Responsibility/Responsibility.php"; $jingli = new CommonManager("李经理"); $zongjian = new MajorDomo("郭总监"); $zongjingli = new GeneralManager("孙总"); //设置直接上级 $jingli->SetHeader($zongjian); $zongjian->SetHeader($zongjingli); //申请 $req1 = new Request(); $req1->requestType = "请假"; $req1->requestContent = "小菜请假!"; $req1->num = 1; $jingli->Apply($req1); $req2 = new Request(); $req2->requestType = "请假"; $req2->requestContent = "小菜请假!"; $req2->num = 4; $jingli->Apply($req2); $req3 = new Request(); $req3->requestType = "加薪"; $req3->requestContent = "小菜请求加薪!"; $req3->num = 500; $jingli->Apply($req3); $req4 = new Request(); $req4->requestType = "加薪"; $req4->requestContent = "小菜请求加薪!"; $req4->num = 1000; $jingli->Apply($req4);
6、策略模式
策略对象依赖注入到context对象,context对象根据它的策略改变而改变它的相关行为(可通过调用内部的策略对象实现相应的具体策略行为)
<?php header('Content-Type:text/html;charset=utf-8'); /** * 策略模式演示代码 * * 为了更好地突出“策略”,我们这里以出行为例演示,日常出行大概分为以下几种工具:自驾车,公交车,地铁,火车,飞机,轮船 * * 下面一起看代码,领会何为策略模式 */ /** * Interface Travel 抽象策略角色 * 约定具体方法 */ interface Travel { public function go(); } /** * Class selfDriving 具体策略角色 * 自驾车 */ class bySelfDriving implements Travel { public function go() { echo '我自己开着车出去玩<br>'; } } /** * Class byBus具体策略角色 * 乘公交 */ class byBus implements Travel { public function go() { echo '我乘公交出去玩<br>'; } } /** * Class byMetro 具体策略角色 * 乘地铁 */ class byMetro implements Travel { public function go() { echo '我乘地铁出去玩<br>'; } } /** * Class byTrain 具体策略角色 * 乘火车 */ class byTrain implements Travel { public function go() { echo '我乘火车出去玩<br>'; } } /** * Class byAirplane 具体策略角色 * 乘飞机 */ class byAirplane implements Travel { public function go() { echo '我乘飞机出去玩<br>'; } } /** * Class bySteamship 具体策略角色 * 乘轮船 */ class bySteamship implements Travel { public function go() { echo '我乘轮船出去玩<br>'; } } /** * Class Mine 环境角色 */ class Mine{ private $_strategy; private $_isChange = false; /** * 构造方法 * 此处使用到了依赖注入和类型约束的概念,详情请参考 * 1.聊一聊PHP的依赖注入(DI) 和 控制反转(IoC) * @link https://segmentfault.com/a/1190000007209266 * 2.浅谈PHP的类型约束 * @link https://segmentfault.com/a/1190000007226476 * * @param Travel $travel */ public function __construct(Travel $travel) { $this->_strategy = $travel; } /** * 改变出行方式 * * @param Travel $travel */ public function change(Travel $travel) { $this->_strategy = $travel; $this->_isChange = true; } public function goTravel() { if ($this->_isChange) { echo '现在改变主意,'; $this->_strategy->go(); } else { $this->_strategy->go(); } } } /** * 客户端使用 */ $strategy = new Mine(new byBus()); // 乘公交 $strategy->goTravel(); // 乘地铁 $strategy->change(new byMetro()); $strategy->goTravel(); // 自驾车 $strategy->change(new bySelfDriving()); $strategy->goTravel(); // 其他根据具体应用选择实现
运行结果
7、装饰器模式
保持接口,增强性能:修饰类继承被修饰对象的抽象父类,依赖被修饰对象的实例(被修饰对象依赖注入),以实现接口扩展
基类传入基本的数据,可通过后面的类进行加工处理,自主组合
8、适配器模式
使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
9、桥接模式
两个维度独立变化,依赖方式实现抽象与实现分离:需要一个作为桥接的接口/抽象类,多个角度的实现类依赖注入到抽象类,使它们在抽象层建立一个关联关系
类的组合完成业务逻辑