PHP中的设计模式
设计模式:提供了一种广泛的可重用的方式来解决我们日常编程中常常遇见的问题。设计模式并不一定就是一个类库或者第三方框架,它们更多的表现为一种思想并且广泛地应用在系统中。它们也表现为模板或者一种模式,可以在多个不同场景下用于解决问题。设计模式可以用于加速开发,并且将很多大的想法或者设计以一种简单的方式实现。当然,虽然设计模式在开发中很有作用,但是千万要避免在不适当的场景误用他们。
设计模式分类 根据目的和范围,设计模式可分为5类。 按照目的分为:创建设计模式,结构设计模式,以及行为设计模式。 按照范围分为:类的设计模式,以及对象设计模式。
按照目的划分
分类
模式
分析
创建设计模式[Creational Patterns]
用于创建对象时的设计模式。更具体一点,初始化对象流程的设计模式。当程序日益复杂时,需要更加灵活地创建对象,同时减少创建时的依赖,而创建设计模式就是解决此问题的一类设计模式
单例模式[Singleton]
工厂模式[Factory]
抽象工厂模式[AbstractFactory]
建造者模式[Builder]
原型模式[Prototype]
结构设计模式[Structural Patterns]
用于继承和接口时的设计模式。结构设计模式用于新类的函数方法设计,减少不必要的类定义,减少代码的冗余
适配器模式[Adapter]
桥接模式[Bridge]
合成模式[Composite]
装饰器模式[Decorator]
门面模式[Facade]
代理模式[Proxy]
享元模式[Flyweight]
行为模式[Behavioral Patterns]
用于方法实现以及对应算法的设计模式,同时也是最复杂的设计模式。行为设计模式不仅仅用于定义类的函数行为,同时也用于不同类之间的协议、通信。
策略模式[Strategy]
模板方法模式[TemplateMethod]
观察者模式[Observer]
迭代器模式[Iterator]
责任链模式[ResponsibilityChain]
命令模式[Command]
备忘录模式[Memento]
状态模式[State]
访问者模式[Visitor]
中介者模式[Mediator]
解释器模式[Interpreter]
按照范围划分
模式
分析
类的设计模式
用于类的具体实现的设计模式。包含了如何设计和定义类,以及父类和子类的设计模式
对象设计模式
用于对象的设计模式。与类的设计模式不同,对象设计模式主要用于运行期对象的状态改变、动态行为变更等。
设计模式实现 单例模式 1 2 3 4 5 6 7 8 9 10 11 12 class Mysql { private static $instance ; public static function getInstance ( ) { if (! (self ::$instance instanceof self )) { self ::$instance = new self (); } return self ::$instance ; } }
工厂模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 interface Factory { public static function createSystem ($type ) ; } class MySystemFactory implements SystemFactory { public static function createSystem ($type ) { $class = \App\Service\ . ucfirst($tpye ) . Services; if (! class_exitsts($class )) { throw new \Exception ('Invild Class' ); } return new $class ; } } $factory = MySystemFactory::create($type );
抽象工厂模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php interface Factory () { public function createSystem ( ) ; public function createSoft ( ) ; } class MacFactory implements Factory { public function createSystem ( ) { return new MacSystem(); } public function createSoft ( ) { return new MacSoft(); } }
Builder(建造者模式) 建造者模式主要创建一些复杂的对象。将一个复杂的对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示的设计模式。
我们这里举一个例子,小王和小明都需要创建个人档案,将个人档案创建成功后,发送给老师,老师处理或者说(评语)个人档案信息。这里有三个角色
角色
解释
创建方式(具体创建方法)
比如:小王需要创建个人档案,个人档案都需要先创建哪些信息,比如性别,年龄,身高,视力等等
创建人(谁来创建)
比如:小王填写了创建成功的个人档案信息
创建什么产品
比如:创建一个个人档案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 <?php class PersonFile { public $record ; public function __construct ( ) { $this ->record = []; } public function setAttr ($keyword , $value ) { $this ->record[$keyword ] = $value ; } } abstract class AbstractBuild () { public function setHigh ( ) ; public function setSex ( ) ; public function setName ( ) ; } class PersonFileBuild extends AbstractBuild { public $personFile ; public function __construct (PersonFile $file ) { $this ->personFile = $file ; } public function setHigh ($value ) { $this ->personFile->setAttr('high' , $value ); } public function setSex ($value ) { $this ->personFile->setAttr('sex' , $value ); } public function setName ($value ) { $this ->personFile->setAttr('name' , $value ); } } class XWFile { public $createRes ; public function __construct (AbstractBuild $builder ) { $builder ->setHigh('1.81' ); $builder ->setSex(1 ); $builder ->setName('小王' ); $this ->createResl = $builder ; } public function getXWFile ( ) { return $this ->createRes; } } $XwPersonFile = (new XWFile(new PersonFileBuild(new PersonFile())))->getXWFile();
适配器模式 简单来讲,对外层进行封装,同样的功能把不能用的接口封装成可以用的接口就可以了。
假设这里对返回数据进行format格式化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 interface Format { public function Format (string $cnt ) ; } class UTF8Format implements Format { public function format (string $cnt ) { return '将格式转化为了utf8' ; } } class MainServers { public function content ($cnt ) { (new UTF8Format($content ))->getContent(); } }
观察者模式 开篇从名字说起,观察者模式中的观察者三个字信息量很大。玩过网络游戏的人都知道,即便是斗地主,除了玩家,还有一个角色叫“观察者”。在我们今天讨论的模式设计中,观察者也是如此。首先要有一个主题,观察者才能搬着小板凳聚在一起,其次,观察者还必须要有自己的操作。否则你聚在一起也没有什么意义。
从面向过程的角度来看,首先是观察者向主题注册,注册完之后,主题在通知观察者做出相应的操作,整个事情就完了。
从面向对象的角度来看,主题提供注册和通知的接口,观察者提供自身操作的接口。观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者,耦合度相当之低。接下来我们看一下实现过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 interface Theme { public function register (Observer $observer ) ; public function notify ( ) ; } interface Observer { public function opt ( ) ; } class Observer527 implements Observer { public function opt ( ) { echo "太无聊了,尿点" ; } } class Observer517 implements Observer { public function opt ( ) { echo "太可怕了" ; } } class Observer577 implements Observer { public function opt ( ) { echo "没意思" ; } } class GhostFilmTheme implements Theme { public $observers = []; public function register (Observer $observer ) { $this ->observers[] = $observer ; } public function notify ( ) { foreach ($this ->observers as $observer ) { $observer ->opt(); } } } $film = new GhostFilmTheme();$film ->register(new Observer527);$film ->register(new Observer517);$film ->register(new Observer577);$film ->notify();
注册树模式 本人感觉无聊至极的模式,简单来讲就是将数组赋值取出扩展成类,调用的方式来取出赋值. 注意:数组是放在静态变量中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Register { protected static $objects ; public static function set ($alias , $object ) { self ::$objects [$alias ] = $object ; } public static function get ($alias ) { return self ::$objects [$alias ]; } public static function unset ($alias ) { unset (self ::$objects [$alias ]); } } Register::set('rand' , 'xxxxx' ); pr(Register::get('rand' ));
桥接模式 桥接模式主要解决:解耦一个对象的实现与抽象,这样两者可以独立地变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 interface Format { public function format (string $text ) ; } class JsonFormat implements Format { public function format (string $text ) { return json_encode($text ); } } class HTMLFormat implements Format { public function format (string $text ) { return htmlspecialchars($text ); } } abstract class Service { protected $implementation ; public function __construct (Format $format ) { $this ->implementation = $format ; } abstract public function get ( ) ; } class XWService extends Service { public function get ($text ) { return $this ->implementation->format($text ); } } new XWService(new JsonFormat)->get('hello world' );
装饰器模式 装饰器模式允许我们根据运行时不同的情景动态地为某个对象调用前后添加不同的行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 interface Component { public function operation ( ) ; } abstract class Decorator implements Component { protected $component ; public function __construct (Component $component ) { $this ->component = $component ; } public function operation ( ) { $this ->component->operation(); } } class ConcreteDecoratorA extends Decorator { public function __construct (Component $component ) { parent ::__construct($component ); } public function operation ( ) { parent ::operation(); $this ->addedOperationA(); } public function addedOperationA ( ) { echo "A加点" ; } } class ConcreteDecoratorB extends Decorator { public function __construct (Component $component ) { parent ::__construct($component ); } public function operation ( ) { parent ::operation(); $this ->addedOperationB(); } public function addedOperationB ( ) { echo "ceshi B" ; } } class ConcreteComponent implements Component { public function operation ( ) { } } $component = new ConcreteComponent();$decoratorA = new ConcreteDecoratorA($component )->operation();$decoratorB = new ConcreteDecoratorB($decoratorA )->operation();
依赖注入 没什么说的,一直在用,一个类必须依赖另一个类,以参数的形式注入进另一个类中。
代理模式(Proxy) 个人理解:代理模式就是访问代理对象,从而添加一些额外的功能,或者说限制访问对象,这种是不是类似于中间件?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 abstract class Subject { abstract public function action ( ) ; } class RealSubject extends Subject { public function __construct ( ) { } public function action ( ) { } } class ProxySubject extends Subject { private $realSubject = NULL ; public function __construct ( ) { } public function action ( ) { $this ->beforeAction(); if (is_null($this ->realSubject)) { $this ->realSubject = new RealSubject(); } $this ->realSubject->action(); $this ->afterAction(); } private function beforeAction ( ) { echo "action方法调用前操作" ; } private function afterAction ( ) { echo "action方法后调用" ; } } $Subject = new ProxySubject();$Subject ->action();
策略模式 类似于laravel的依赖注入,策略模式主要为了让客户类能够更好地使用某些算法而不需要知道其具体的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php interface Strategy { public function do_method ( ) ; } class StrategyA implements Strategy { public function do_method ( ) { echo "do method A" ; } } class StrategyB implements Strategy { public function do_method ( ) { echo "do method B" ; } } class Question { private $strategy ; public function __construct (Strategy $strategy ) { $this ->strategy = $strategy ; } public function handle_question ( ) { $this ->strategy->do_method(); } } $strategy = new Question(new StrategyA)->handle_question();
模板方法模式 就是利用抽象方法实现具体功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php abstract class AbstractClass { public function templateMethod ( ) { $this ->primitiveOperation1(); $this ->primitiveOperation2(); } abstract protected function primitiveOperation1 ( ) ; abstract protected function primitiveOperation2 ( ) ; } class ConcreteClass extends AbstractClass { protected function primitiveOperation1 ( ) {} protected function primitiveOperation2 ( ) {} } $class = new ConcreteClass();$class ->templateMethod();?>