观察者模式

概念 观察者模式属于行为模式,是定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。 当一个对象状态发生改变后,会影响到其他几个对象的改变,这时候可以用观察者模式。 观察者模式符合接口隔离原则,实现了对象之间的松散耦合。 角色 抽象主题(subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。 具体主题(ConcreteSubjest):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。 <?php //抽象主题 interface Subject { //新增观察者 public function attach(Observer $observer); //移除观察者 public function detach(Observer $observer); //通知观察者 public function notifyObserver(); } //具体主题 class ConcreteSubjest implements Subject { //储存观察者 private $observers; public function __construct() { $this->observers = []; } //新增观察者 public function attach(Observer $observer) { return array_push($this->observers, $observer); } //移除观察者 public function detach(Observer $observer) { //检查观察者是否存在观察者数组中,返回索引值 $index = array_search($observer, $this->observers); if ($index === false) { return false; } else { unset($this->observers[$index]); return true; } } //通知观察者 public function notifyObserver() { if (!...

March 26, 2022 · 1 min · ZhaoGuibin

策略模式

概念 将一组特定的行为和算法封装成类,以适应某些特定的上下文环境,并让它们可以相互替换,这种模式就是策略模式。 简单理解就是 有n个做法供你选择,根据你的需要选择某个策略得到结果 优点 使用设计模式之后,我们的代码冗余和耦合度变低,每个策略模块完成对应的功能。 当然缺点就是一个功能我们就要响应制作一个策略类,但是我们统观MVC架构当中(Thinkphp,Yii2),一个控制器对应一个视图,其实也是策略模式的体现了。 <?php interface UserInterface { public function showAd(); public function showCategory(); } //男性用户实现接口 class MaleUser implements UserInterface { public function showAd() { echo '电子产品'; } public function showCategory() { echo "PS5,PC,Switch"; } } //女性用户实现接口 class FemaleUser implements UserInterface { public function showAd() { echo '化妆品'; } public function showCategory() { echo "口红,面膜"; } } //客户端实现,根据性别不同推荐不同内容 $sex = 'male'; if ($sex == 'male') { $user = new MaleUser(); } else { $user = new FemaleUser(); } $user->showAd(); $user->showCategory();

March 26, 2022 · 1 min · ZhaoGuibin

装饰器模式

概念 装饰器模式又叫装饰者模式。装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。 实例 组件对象的接口:可以给这些对象动态的添加职责 所有装饰器的父类:需要定义一个与组件接口一直的接口,并持有一个component对象,该对象其实就是被装饰的对象。 具体的装饰器类:实现具体要向被装饰对象添加的功能。用来装饰具体的组件对象或者另外一个具体的装饰器对象。 使用场景 需要动态的给一个对象添加功能,这些功能可以再动态的撤销 需要添加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。 <?php //组件对象接口 interface IComponent { //动态给对象添加功能 public function display(); } //待装饰的对象 class Person implements IComponent { protected $name; public function __construct($name) { $this->name = $name; } public function display() { echo '装饰的' . $this->name; } } //所有装饰器的父类 class Clothes implements IComponent { protected $component; public function Decorate(IComponent $component) { $this->component = $component; } public function display() { if (!empty($this->component)) { $this->component->display(); } } } //具体的装饰器 class Pixie extends Clothes { public function display() { echo '皮鞋'; parent::display(); } } class Waitao extends Clothes { public function display() { echo '外套'; parent::display(); } } //客户端 $gd = new Person('狗蛋'); $px = new Pixie(); $px->Decorate($gd); $px->display(); $wt = new Waitao(); $wt->Decorate($gd); $wt->display();

March 24, 2022 · 1 min · ZhaoGuibin

注册树模式

概念 注册树模式也叫注册模式或注册器模式,顾名思义,注册树就是把对象实例注册到一棵全局的对象树上,需要对象的时候就从树上取下来,就好比树上长的果子,需要的时候就摘一个下来,只是这个对象树果子是摘不完的。 作用 不管是单例模式还是工厂模式建立的对象,都没有得到很好的管理,用了注册树模式,就可以把创建出来的对象注册到全局树上,需要的时候取下来用,可以很好的管理创建的对象。 <?php class DbMysql { public function conn() { echo 'mysql conn'; } } class DbSqlite { public function conn() { echo 'sqlite conn'; } } class MysqlFactory { public static function getIns() { return new DbMysql(); } } class SqliteFactory { public static function getIns() { return new DbSqlite(); } } //注册树实现存储对象(IOC控制反转思想) class RegisterTree { 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]); } } //注册 RegisterTree::set('mysql', MysqlFactory::getIns()); RegisterTree::set('sqlite', SqliteFactory::getIns()); //客户端 // $mysql = RegisterTree::get('mysql'); // $mysql->conn(); // $sqlite = RegisterTree::get('sqlite'); // $sqlite->conn(); class Facade { public static $mysql; public static $sqlite; public function __construct() { self::$mysql = RegisterTree::get('mysql'); self::$sqlite = RegisterTree::get('sqlite'); } } new Facade(); Facade::$mysql->conn(); Facade::$sqlite->conn();

March 24, 2022 · 1 min · ZhaoGuibin

门面模式

概念 门面模式(facade)又称外观模式,用于为子系统中的一组接口提供一个一致的界面。门面模式定义了一个高层接口,这个接口使得子系统更加容易使用;引入门面角色之后,用户只需要直接与门面角色交互,用户与子系统之间的复杂关系由门面角色来实现,从而降低了系统的耦合度。 作用 为一些复杂的子系统提供一组接口。 提高子系统的独立性 在层次化结构中,可以使用门面模式定义系统的每一层的接口 优点 它对于客户屏蔽了子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。 实现了子系统与客户之间的松耦合关系。 如果应用需要,它并不限制它们使用子系统类。因此可以在系统易用性与能用性之间加以选择。 <?php class Camera { public function turnOn() { echo 'turn on camera'; } public function turnOff() { echo 'turn off camera'; } } class Light { public function turnOn() { echo 'turn on light'; } public function turnOff() { echo 'turn off light'; } } //门面类 class Facade { private $camera; private $light; public function __construct() { $this->camera = new Camera(); $this->light = new Light(); } //启动接口 public function activate() { $this->camera->turnOn(); $this->light->turnOn(); } //关闭接口 public function deactivate() { $this->camera->turnOff(); $this->light->turnOff(); } } //客户端 class Client { private static $securit; public static function main() { self::$securit = new Facade(); self::$securit->activate(); self::$securit->deactivate(); } } Client::main();

March 24, 2022 · 1 min · ZhaoGuibin

管道模式

概念 管道(pipeline)设计模式流水线模式就是将数据传递到一个任务序列中,管道扮演着流水线的角色,数据在这里被处理然后传递到下一个步骤 释义 管道,顾名思义,就是一个长长的流水管道,只不过加了许多阀门。所以管道模式大致需要三个角色:管道、阀门、载荷(流水)。 目的是在管道中对载荷进行一系列的处理。因为可以对过滤器进行动态的添加,所以对载荷的处理可以变得更加灵活。但同时带来的问题是,在过滤器过多时,很难把握整体的处理逻辑。而且在某一个过滤器对载荷处理后,因为载荷改变,会造成下一个过滤器中的逻辑出错。 <?php //管道接口 interface PipelineBuilder { public function __construct($payload); //$payload载荷 public function pipe(StageBuilder $stage); //管道与阀门 public function process(); //过程 } //实现管道接口 class Pipeline implements PipelineBuilder { protected $payload; protected $pipes = []; public function __construct($payload) { $this->payload = $payload; } public function pipe(StageBuilder $stage) { $this->pipes[] = $stage; return $this; } public function process() { foreach ($this->pipes as $pipe) { call_user_func([$pipe, 'handle'], $this->payload); } } } //阀门类 interface StageBuilder { public function handle($payload); } //实现 class StageOneBuilder implements StageBuilder { public function handle($payload) { echo 'one-'; } } class StageTwoBuilder implements StageBuilder { public function handle($payload) { echo 'two-'; } } //客户端使用 $pipeline = new PipeLine('step'); $pipeline->pipe(new StageOneBuilder())->pipe(new StageTwoBuilder())->process();

March 24, 2022 · 1 min · ZhaoGuibin

代理模式

概念 构建了透明置于两个不同对象之内的一个对象,从而能够截取或代理这两个对象间的通信或访问。 应用场景 远程代理:也就是为了一个对象在不同地址空间提供局部代表。隐藏一个对象存在于不同地址空间的事实。 虚拟代理:根据需求来创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。 安全代理:用来控制真实对象的访问对象。 智能指引:当调用真实对象的时候,代理处理一些事情。 <?php //真实类 interface Subject { public function request(); } class RealSubject implements Subject { public function request() { echo '真实的操作'; } } //代理模式代理真实类 class Proxy implements Subject { protected $realSubject; public function __construct() { $this->realSubject = new RealSubject(); } public function request() { echo '代理操作'; $this->realSubject->request(); } } //客户端 $proxy = new Proxy(); $proxy->request(); 注意事项 代理模式的实现其实非常简单,或许你在不经意间经常会用到 请注意代理模式与装饰器、适配器的区别 装饰器:一般是对对象进行装饰,其中的方法行为会有增加,以修饰对象为主 适配器:一般会改变方法行为,目的是保持接口的统一但得到不同的实现 代理模式有几种形式:远程代理(例如:第三方接口SDK)、虚代理(例如:异步加载图片)、保护代理&智能指引(例如:权限保护),而我们代码实现的最普通的代理,其实就是让代理类来代替真实类的操作

March 24, 2022 · 1 min · ZhaoGuibin

适配器模式

概念 将某个类的接口转换成与另一个接口兼容。适配器通过将原始接口进行转换,给用户提供一个兼容接口,使得原来因为接口不同而无法一起使用的类可以得到兼容。 应用场景 老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。 <?php interface Weather { public function show(); } class PhpWeather implements Weather { public function show() { $weatherInfo = ['weather' => '雨', 'tep' => 6, 'wind' => 3]; return serialize($weatherInfo); } } //兼容模式 使得java能够直接使用 interface WeatherA { public function getWeather(); } class JavaWeather implements WeatherA { protected $weather; public function __construct(Weather $weather) { $this->weather = $weather; } public function getWeather() { $info = unserialize($this->weather->show()); return json_encode($info); } } $weather = new PhpWeather(); // $info = unserialize($weather); // var_dump($info); $java_weather = new JavaWeather($weather); $info = json_decode($java_weather->getWeather()); var_dump($info);

March 23, 2022 · 1 min · ZhaoGuibin

工厂模式

概念 工厂模式是我们最常用的实例化对象模式,是用工厂方法代替new操作的一种模式。 好处 使用工厂模式的好处是,如果你想要更改所实例化的类名等,则只需要更改该工厂方法内容即可,不需要逐一寻找代码中具体实例化的地方(new 处)修改了。为系统结构提供灵活的动态扩展机制,减少了耦合。 分类 简单工厂模式 工厂方法模式 抽象工厂模式 简单工厂模式 简单工厂模式又称静态工厂模式,之所以可以这么说,是因为简单工厂模式是通过一个静态方法来创建对象的 <?php class DbMysql { public function conn() { echo "连接MySQL"; } } class DbSqlite { public function conn() { echo "连接SQLite"; } } class DbFactory { public static function createIns($type) { switch ($type) { case 'mysql': return DbMysql(); break; case 'sqlite': return new DbSqlite(); break; default: throw new ErrorException('类型错误'); } } } $mysql = DbFactory::createIns('mysql'); $mysql->conn(); $sqlite = DbFactory::createIns('sqlite'); $sqlite->conn(); 工厂方法模式...

March 22, 2022 · 2 min · ZhaoGuibin

单例模式

概念 是一种类的设计只会最多产生一个对象的设计思想 作用 php的应用主要在于数据库应用,所以一个应用中会存在大量的数据库操作,使用单例模式,则可以避免大量的new操作消耗的资源。 如果系统中需要有一个类来全局控制某些配置信息,那么使用单例模式可以很方便的实现。 再一次页面请求中,便于进行调试,因为所有的代码都会集中在一个类里面,我们可以在类中设置钩子,输出日志,从而避免到处var_dump,echo。 应用场景 数据库连接,缓存操作,分布式储存 单例模式的要点 构造函数需要标记为private(访问控制:防止外部代码使用new操作符创建对象),单例类不能在其他类中实例化,只能被其自身实例化。 拥有一个保存类的实例的静态成员变量。 拥有一个访问这个实例的公共的静态方法(常用getInstance()方法进行实例化单例类,通过instanceof操作符可以检测到类是否已经被实例化) 简称 三私一公: 私有化构造方法:不让在外部产生多个对象 私有化克隆方法:不允许对象被克隆产生新对象 私有化静态属性:运行进入类内部产生对象 公有化静态方法:保存已经产生的对象 <?php //单例 class Uni{ //创建静态私有的变量保存该类对象 static private $instance; //参数 private $config; //防止直接创建对象 private function __construct($config){ $this -> config = $config; echo "我被实例化了"; } //防止克隆对象 private function __clone(){ } static public function getInstance($config){ //判断$instance是否是Uni的对象 //没有则创建 if (!self::$instance instanceof self) { self::$instance = new self($config); } return self::$instance; } public function getName(){ echo $this -> config; } } $db1 = Uni::getInstance(1); $db1 -> getName(); echo "<br>"; $db2 = Uni::getInstance(4); $db2 -> getName(); /** *运行结果: *我被实例化了1 *1 *$db1创建对象后,参数是1 *$db2没有创建对象,而是直接使用$instance保存的唯一对象,所以输出的参数并没有变为4; */

March 22, 2022 · 1 min · ZhaoGuibin