PHP常见的设计模式
设计模式六大原则
开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象.
依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
迪米特法则:一个对象应该对其他对象保持最少的了解。
1.单例设计模式(Singleton)
所谓单例模式,即在应用程序中最多只有该类的一个实例存在,一旦创建,就会一直存在于内存中!
应用场景:
单例设计模式常应用于数据库类设计,采用单例模式,只连接一次数据库,防止打开多个数据库连接。
一个单例类应具备以下特点:
单例类不能直接实例化创建,而是只能由类本身实例化。因此,要获得这样的限制效果,构造函数必须标记为private,从而防止类被实例化。
需要一个私有静态成员变量来保存类实例和公开一个能访问到实例的公开静态方法。
在PHP中,为了防止他人对单例类实例克隆,通常还为其提供一个空的私有__clone()
方法。
单例模式的例子:
<?php /**
* Singleton of Database
*/
class Database
{ // We need a static private variable to store a Database instance. privatestatic $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.工厂设计模式
要是当操作类的参数变化时,只用改相应的工厂类就可以
工厂设计模式常用于根据输入参数的不同或者应用程序配置的不同来创建一种专门用来实例化并返回其对应的类的实例。
使用场景:使用方法 new实例化类,每次实例化只需调用工厂类中的方法实例化即可。
优点:由于一个类可能会在很多地方被实例化。当类名或参数发生变化时,工厂模式可简单快捷的在工厂类下的方法中 一次性修改,避免了一个个的去修改实例化的对象。
我们举例子,假设矩形、圆都有同样的一个方法,那么我们用基类提供的API来创建实例时,通过传参数来自动创建对应的类的实例,他们都有获取周长和面积的功能。
例子
<?php 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()) { case1: return newCircle(func_get_arg(0)); case2: return newRectangle(func_get_arg(0), func_get_arg(1)); default: # code... 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);
3.观察者设计模式
观察者模式是挺常见的一种设计模式,使用得当会给程序带来非常大的便利,使用得不当,会给后来人一种难以维护的想法。
使用场景:用户登录,需要写日志,送积分,参与活动 等使用消息队列,把用户和日志,积分,活动之间解耦合
什么是观察者模式?一个对象通过提供方法允许另一个对象即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。观察者模式是一种事件系统,意味着这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;观察者模式为您提供了避免组件之间紧密耦。看下面例子你就明白了!
<?php /*
观察者接口
*/
interface InterfaceObserver
{ function onListen($sender, $args); function getObserverName();
} // 可被观察者接口
interface InterfaceObservable
{ function addObserver($observer); function removeObserver($observer_name);
} // 观察者抽象类
abstract class Observer implements InterfaceObserver
{ protected $observer_name; function getObserverName() { return $this->observer_name; } function onListen($sender, $args) { }
} // 可被观察类
abstract class Observable implements InterfaceObservable
{ protected $observers = array(); public function addObserver($observer) { if ($observerinstanceofInterfaceObserver) { $this->observers[] = $observer; } } public function removeObserver($observer_name) { foreach ($this->observersas $index => $observer) { if ($observer->getObserverName() === $observer_name) { array_splice($this->observers, $index, 1); return; } } }
} // 模拟一个可以被观察的类
class A extends Observable
{ public function addListener($listener) { foreach ($this->observersas $observer) { $observer->onListen($this, $listener); } }
} // 模拟一个观察者类
class B extends Observer
{ protected $observer_name = 'B'; public function onListen($sender, $args) { var_dump($sender); echo "<br>"; var_dump($args); echo "<br>"; }
} // 模拟另外一个观察者类
class C extends Observer
{ protected $observer_name = 'C'; public function onListen($sender, $args) { var_dump($sender); echo "<br>"; var_dump($args); echo "<br>"; }
} $a = new A();
// 注入观察者
$a->addObserver(new B());
$a->addObserver(new C()); // 可以看到观察到的信息
$a->addListener('D'); // 移除观察者
$a->removeObserver('B'); // 打印的信息:
// 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"
4.适配器模式
将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作。
应用场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。
例如:php连接数据库的方法:mysql,,mysqli,pdo,可以用适配器统一
//老的代码 class User { private $name; function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } }
//新代码,开放平台标准接口 interface UserInterface { function getUserName(); } class UserInfo implements UserInterface { protected $user; function __construct($user) { $this->user = $user; } public function getUserName() { return $this->user->getName(); } }
$olduser = new User('张三'); echo $olduser->getName()."n"; $newuser = new UserInfo($olduser); echo $newuser->getUserName()."n";
5.策略模式
将一组特定的行为和算法封装成类,以适应某些特定的上下文环境。
使用场景:个人理解,策略模式是依赖注入,控制反转的基础
例如:一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有广告位展示不同的广告
MaleUserStrategy.php
<?php namespace IMooc;
class MaleUserStrategy implements UserStrategy { function showAd() { echo "IPhone6"; } function showCategory() { echo "电子产品"; }
}
FemaleUserStrategy.php
<?php namespace IMooc; class FemaleUserStrategy implements UserStrategy { function showAd() { echo "2014新款女装"; } function showCategory() { echo "女装"; }
}
UserStrategy.php
<?php namespace IMooc; interface UserStrategy { function showAd(); function showCategory();
}
<?php
interface FlyBehavior{ public function fly();
} class FlyWithWings implements FlyBehavior{ public function fly(){ echo "Fly With Wings \n"; }
} class FlyWithNo implements FlyBehavior{ public function fly(){ echo "Fly With No Wings \n"; }
}
class Duck{ private $_flyBehavior; public function performFly(){ $this->_flyBehavior->fly(); } public function setFlyBehavior(FlyBehavior $behavior){ $this->_flyBehavior = $behavior; }
} class RubberDuck extends Duck{
}
// Test Case
$duck = new RubberDuck(); /* 想让鸭子用翅膀飞行 */
$duck->setFlyBehavior(new FlyWithWings());
$duck->performFly(); /* 想让鸭子不用翅膀飞行 */
$duck->setFlyBehavior(new FlyWithNo());
$duck->performFly();
6.装饰器模式
使用场景:当某一功能或方法draw,要满足不同的功能需求时,可以使用装饰器模式;实现方式:在方法的类中建addDecorator(添加装饰器),beforeDraw,afterDraw 3个新方法, 后2个分别放置在要修改的方法draw首尾.然后创建不同的装器类(其中要包含相同的,beforeDraw,afterDraw方法)能过addDecorator添加进去,然后在beforeDraw,afterDraw中循环处理,与观察者模式使用有点相似
1.装饰器模式(Decorator),可以动态地添加修改类的功能
2.一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重新实现类的方法
3.使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性
DrawDecorator.php
<?php
namespace IMooc; interface DrawDecorator
{ function beforeDraw(); function afterDraw();
}
Canvas.php
<?php
namespace IMooc; class Canvas
{ public $data; protected $decorators = array(); //Decorator 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 addDecorator(DrawDecorator $decorator) { $this->decorators[] = $decorator; } function beforeDraw() { foreach($this->decorators as $decorator) { $decorator->beforeDraw(); } } function afterDraw() { $decorators = array_reverse($this->decorators); foreach($decorators as $decorator) { $decorator->afterDraw(); } } function draw() { $this->beforeDraw(); foreach($this->data as $line) { foreach($line as $char) { echo $char; } echo "<br />\n"; } $this->afterDraw(); } function rect($a1, $a2, $b1, $b2) { foreach($this->data as $k1 => $line) { if ($k1 < $a1 or $k1 > $a2) continue; foreach($line as $k2 => $char) { if ($k2 < $b1 or $k2 > $b2) continue; $this->data[$k1][$k2] = ' '; } } }
}
ColorDrawDecorator.php
<?php
namespace IMooc; class ColorDrawDecorator implements DrawDecorator
{ protected $color; function __construct($color = 'red') { $this->color = $color; } function beforeDraw() { echo "<div style='color: {$this->color};'>"; } function afterDraw() { echo "</div>"; }
}
index.php
<?php
define('BASEDIR', __DIR__);
include BASEDIR.'/IMooc/Loader.php';
spl_autoload_register('\\IMooc\\Loader::autoload'); $canvas = new IMooc\Canvas();
$canvas->init();
$canvas->addDecorator(new \IMooc\ColorDrawDecorator('green'));
$canvas->rect(3,6,4,12);
$canvas->draw();
PHP常见的设计模式相关推荐
- php mysql设计中常问_PHP开发中常见的设计模式
一.工厂模式 工厂模式是我们最常用的实例化对象模式,是用工厂方法代替new操作的一种模式. 使用工厂模式的好处是,如果你想要更改所实例化的类名等,则只需更改该工厂方法内容即可,不需逐一寻找代码中具体实 ...
- 常见的设计模式和应用场景
常见的设计模式和应用场景 单例模式 原型模式 命令模式 六大设计原则 1. 单一职责原则 2. 开闭原则 3. 里氏替换原则 4. 依赖倒置原则 5. 接口隔离原则 6. 迪米特法则 设计模式从大的维 ...
- java常见的设计模式
在了解java常见的设计模式之前,我们要了解三个问题, 1.为什么要了解设计模式? 2.这些设计模式的是根据什么原则来设计的? 3.有哪些常见的设计模式? 为什么要了解设计模式? 因为设计模式代表了最 ...
- python算法基础设计模式,python常见的设计模式
Python有设计模式么 Python设计模式主要分为三大类:创建型模式.结构型模式.行为型模式;三 大类中又被细分为23种设计模式,以下这几种是最常见的. 单例模式:是一种常用的软件设计模式,该模式 ...
- iOS常见的设计模式:工厂设计模式
iOS常见的设计模式:工厂设计模式 简单工厂模式: 简单工厂模式(Simple Factory Pattern):专门定义一个类(工厂类)来负责创建其他类的实例.可以根据创建方法的参数来返回不同类的实 ...
- Spring中常见的设计模式
Spring中常见的设计模式 1.Java设计模式 设计模式(Design Pattern)是解决特定问题的一系列套路.它不是语法规定,而是一套用来提高代码可复用性.可维护性.可读性.稳健性以及安全性 ...
- 9种前端常见的设计模式
1. 外观模式 外观模式是最常见的设计模式之一,它为子系统中的一组接口提供一个统一的高层接口,使子系统更容易使用.简而言之外观设计模式就是把多个子系统中复杂逻辑进行抽象,从而提供一个更统一.更简洁.更 ...
- Android开发中常见的设计模式
对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次.而在android开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...
- iOS中常见的设计模式(MVC/单例/委托/观察者)
关于设计模式这个问题,在网上也找过一些资料,下面是我自己总结的,分享给大家 如果你刚接触设计模式,我们有好消息告诉你!首先,多亏了Cocoa的构建方式,你已经使用了许多的设计模式以及被鼓励的最佳实践. ...
- javascript常见的设计模式
为什么80%的码农都做不了架构师?>>> <Practical Common Lisp>的作者 Peter Seibel 曾说,如果你需要一种模式,那一定是哪里出了 ...
最新文章
- 数据结构与算法——线性结构——线性表及其表示
- 因深度学习成就,香港大学罗平入选《麻省理工科技评论》亚太区「35 岁以下创新者」榜单
- ASP.NET Menu控件子菜单弹出导致页面出现滚动条问题
- 测试框架 Jest 实例教程
- Mysql之复制一张表的内容到新表中
- WebRTC 的版本号与代码分支
- 为什么我们需要Maven
- python3 class init_python3 module中__init__.py的需要注意的地方
- Python之数据分析(Numpy中读取与保存数据文件、将数据文件制成K线图)
- Java -- Thread中start和run方法的区别
- php调用声卡,图文讲解美国ART USB Dual Pre声卡多种使用方法!
- android 翻译功能开发,Android使用有道翻译API实现在线翻译功能
- 2020switch电信最快的dns_《2020switch电信最快的dns》电影_2020switch电信最快的dns正片免费观看-扬州人才服务网...
- 如何将pdf转换成jpg,转换达人教你一招搞定
- vue之设置背景图片自适应屏幕
- pythonwhile循环语句_Python While循环语句
- SpringBoot之从零搭建网站(可提供源码)
- Duplicate Net Names Wire AVCC
- DB2处理数据由原来六小时优化到二十分钟(一)
- 征途2经典版服务器双线哪个稳定,征途,别毁了自己和曾经的经典
热门文章
- 重庆专科计算机专业学校哪个最好,重庆十大大专排名(含分数线2021年参考)-重庆最好的全日制专科学校...
- Java-面向对象进阶
- 追女孩要用到的短信24条
- 玩战地风云2042的感想
- python // 与 / 的含义
- R语言基础题及答案(六)——R语言与统计分析第六章课后习题(汤银才)
- 什么是端口转发?什么是端口映射?如何设置端口映射?
- android开发笔记之 Android代码混淆打包
- 我的位置的特殊服务器,场景名:我的门派我做主 服务器:书写 特殊:1.1修身养性...
- caffe源码学习——1.熟悉protobuf,会读caffe.proto