设计模式本质上就是一种模式,只要了解每个模式个什么意思和作用就行,下面的代码例子也是为了方便理解,所以写的尽量简洁明了
1.单例模式
说明:某一个类全局只存在一个实例,并且不会被创建副本,因为不能被实例化了所以需要为外部提供一个获取实例的入口(一个静态方法)
作用:(1)在一次运行中,不会被实例化多次可以减少内存的开销。
(2)以数据库为例,只实例化一次还可以省去链接,断开等重复动作
(3)因为只有一个实例,可以全局的控制配置信息
实现:
<?php class Single { static private $instance; //实例 private $conf; //配置 public $param; private function __construct($conf) //防止new { $this->conf = $conf; } private function __clone() {} //防止clone private function __sleep() {} //防止序列化 static public function getInstance($conf) { if (! self::$instance) { self::$instance = new self($conf); } return self::$instance; } } //测试 $s1 = Single::getInstance(array()); $s2 = Single::getInstance(array()); $s1->param = 's1'; echo $s1->param; //s1 echo $s2->param; //s1 $s2->param = 's2'; echo $s1->param; //s2 echo $s2->param; //s2 ?>
2.工厂模式
说明:当需要一个实例的不需要new,直接属于置顶参数从工厂模式中调取就行了
作用:(1)便于管理,易于扩展
(2)外部不需要关心类的名称和文件位置,只要传入对应编号就行了
实现:
<?php class class1{}; class class2{}; class class3{}; class Factory { private static $classes = [ //可返回类 1 => 'class1', 2 => 'class2', 3 => 'class3', ]; static public function create($num) { if (isset(self::$classes[$num])) { return new self::$classes[$num](); } return false; } } $class = Factory::create(1); ?>
3.观察者模式
说明:多个观察者观察一个主题对象,当主题对象发生改变的时候(这里只是指一个触发条件),会通知观察者让观察者(其实就是轮询去执行观察者的一个function)
作用:看起来可能还是模模糊糊的,但看一下代码就能理解了,本质上很简单。举个例子假如我是个主题对象,我进门是一个触发条件,灯就打开了(灯是个观察者),电视就打开了(电视是个观察者)等等。。 这里还是看你注册了多少个观察者
在项目中,我们会在用户注册后还有有一系列动作(比如发站内信,发新人券什么的),可以把这些动作注册成观察者,观察到用户注册之后自动就只行了
实现:
<?php //这里可以用接口类限制下必须实现哪些方法,为了看起来简洁些就不整那些没用的了 class Action { private $observers = []; //注册一个观察者 public function attach($observer) { $this->observers[] = $observer; } //注销一个观察者 public function detach($observer) { $k = array_search($observer, $this->observers); if ($k) unset ($this->observers[$k]); } //通知 public function notify() { foreach ($this->observers as $observer) { $observer->update(); } } } //观察者们 class Observer1 { function update(){echo 'Observer1';} } class Observer2 { function update(){echo 'Observer2';} } $action = new Action(); $action->attach(new Observer1()); $action->attach(new Observer2()); $action->notify(); ?>
补充(个人观点):我觉得叫观察者不是很准确,因为从实现来看并不是观察者主动触发的,而是被通知过才会有动作。他们也并没有执行观察这个动作。如果真是想完成观察这个动作我能想到的也就只能一直while了,while的条件可以用指针指向主题对象的某一个特征值,观察主题有没有变化。但这样开销大了。
4.适配器模式
说明:可以当做一个中间件,对以前的对象再二次处理一下形成一个新接口
作用:为了满足新的需求,要从老接口衍生出新的接口,为了省去大量重复代码和灵活性新接口会复用老接口代码,并做二次处理。假如我们以前有三个接口,分别是炒饭、炒面、炒粉。最近发现用户喜欢吃肥牛,我们就加了三个新品肥牛炒饭、肥牛炒面、肥牛炒粉。如果把所有老接口都改一下代价就比较大了,而且如果还是有客户点炒饭,炒面 我们还要考虑兼容性。所以如果有用户点肥牛炒饭 我们就调老接口生产一个炒饭然后在往里加肥牛就好了(说起来比较绕,其实原理很简单 看一下代码就明白了)
实现:
<?php class Rice { public function dosomething() { return 'fry rice'; // 炒饭 } } class Noodles { public function dosomething() { return 'fry noodles'; //炒面 } } class Adapter //适配器 { private $obj; public function __construct($obj) { $this->obj = $obj; } public function dosomething() { $res = $this->obj->dosomething(); return $res . ' add fat cattle'; //加肥牛 } } $adapter1 = new Adapter(new Rice()); $adapter2 = new Adapter(new Noodles()); echo $adapter1->dosomething(); //fry rice add fat cattle echo $adapter2->dosomething(); //fry noodles add fat cattle ?>
5.策略模式(这个没搞懂他的意义)
说明:可以根据当前环境选择自己需要的功能,自己需要使用哪种方法,就直接new哪个对象了。那些对象也可以交给工厂模式管理
作用:主要是为了防止下文使用 if...else 或 switch...case 所带来的复杂性和臃肿性。我之前一直没搞懂是咋就做到不用if..else了,一直觉得这个像脱裤子放屁(我的理解的不深,可能过个一两年我就意识到他的美好了,到时候我把这里删掉),看代码吧
实现:
<?php //先简单的说明一下,这个例子我想实现两个数字相加,这里我就直接写成方法了,方便一些。 //首先是传统的方法 $num1 = 1; $num2 = 2; function cal($num1, $num2, $oper) { //$oper是符号,根据符号判断用户想做什么,这里不就好多if..else了嘛 if ($oper == '+') { return $num1 + $num2; } else if ($oper == '-') { return $num1 - $num2; } else return false; } //我想让两个数字相加,所以我传的加号 echo cal($num1, $num2, '+'); //-------------------------------------------------------分割线------------------------------------------------------- //现在用策略模式 function add($num1, $num2) { return $num1 + $num2; } function context($num1, $num2, $fun) { return $fun($num1, $num2); } echo context($num1, $num2, add); //这里我直接传add这个function 下游就不用去判断了 直接执行就行了 //补充:上网查了好多(都是互相套,或者拽一些套词,写个demo那么老长 看着也费劲),可能理解的还是不对,这个用对象实现大概也是这么个意思 还是觉得在脱裤子放屁 ?>
6.装饰器模式
说明:对一个类的功能进行修改或者添加
作用:为了应对更多的场景,需要对类的功能进行新增和修改,其实我们也可以采用继承的方式,但假如很多类(继承自同一个接口)都要统一添加和修改一个功能,不是要写很多个子类吗 并且随着扩展功能的增多,子类会很膨胀
实现:
<?php //c1 c2是两个被装饰的类 class C1 { function get() { return 100; } } class C2 { function get() { return 200; } } //这个是装饰器 class Decorator { private $obj; public function __construct($obj) { $this->obj = $obj; } function get() { $res = $this->obj->get(); return $res / 10; } function newGet() { $res = $this->obj->get(); return $res + 1; } } //测试 $obj1 = new Decorator(new C1()); $obj2 = new Decorator(new C2()); echo $obj1->get(); echo $obj1->newGet(); echo $obj2->get(); echo $obj2->newGet(); ?>
补充:看起来是不是和适配器很像,个人总结的两个不同点(1)适配器是为了适配新的环境,入参和调用方式都有可能改变,比如我新增一个type参数,适配器就要为这个做一个拓展。但装饰器不会,调用方式要保证和之前相同,只是为了在之前功能基础上‘装饰’的更漂亮。(2)从定义上看装饰器不仅包括修改,还包括新增