PHP设计模式(2)

xiaoxiao2021-02-27  433

设计模式(二)

一、实验介绍

本此实验将在上一次实验的基础上,继续为大家介绍八种设计模式的要点。

实验环境和编码工具同上一个实验。

二、实验过程

上一个实验的后面部分,向大家介绍了三种结构型模式,那么,本次实验的前面部分也将继续介绍后面的三种结构模式:外观模式,享元模式,代理模式。


外观模式

外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。

举一个简单的例子,相信大家都使用过 C++ 语言,他是一门编译型语言,写完代码之后,我们需要经过编译之后才能运行,在IDE中,会有一个 Build 的按钮,点击它即可完成编译过程,但是这一个简单的动作背后,却是一系列复杂操作的协调配合,至少包括词法分析,语法分析,生成中间代码,生成汇编代码以及链接等操作,作为普通开发人员,我们不必在意这些过程是如何完成的,只需要点击Build按钮,IDE就会自动帮我们完成背后的工作。那么这个Build按钮就是IDE为我们提供的高级接口,通过他来完成各种子系统的协调工作。

角色:

Facade:外观角色,提供高级接口

SubSystem:子系统角色,负责各自的功能实现

UML 类图

示例代码

<?php class SystemA { public function operationA() { echo "operationA <br>"; } } class SystemB { public function operationB() { echo "operationB <br>"; } } class SystemC { public function operationC() { echo "operationC <br>"; } } class Facade { protected $systemA; protected $systemB; protected $systemC; function __construct() { $this->systemA = new SystemA(); $this->systemB = new SystemB(); $this->systemC = new SystemC(); } public function myOperation() { $this->systemA->operationA(); $this->systemB->operationB(); $this->systemC->operationC(); } } $facade = new Facade(); $facade->myOperation();

使用外观模式最大的优点就是子系统与客户端之间是松耦合的关系,客户端不必知道具体有哪些子系统,也无需知道他们是如何工作的,通过引入一个外观类,提供一个客户端间接访问子系统的高级接口。子系统和外观类可以独立运作,修改某一个子系统的内容,不会影响到其他子系统,也不会影响到外观对象。不过它的缺点就是它不够灵活,当需要增加一个子系统的时候,需要修改外观类。

享元模式

享元模式(英语:Flyweight Pattern)是一种软件设计模式)。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。

要理解享元模式,先要理解两个重要的概念:内部状态和外部状态。

内部状态存储于flyweight中,它包含了独立于flyweight场景的信息,这些信息使得flyweight可以被共享。而外部状态取决于flyweight场景,并根据场景而变化,因此不可共享。用户对象负责在必要的时候将外部状态传递给flyweight。

角色

Flyweight: 抽象享元类

ConcreteFlyweight: 具体享元类

UnsharedConcreteFlyweight: 非共享具体享元类

FlyweightFactory: 享元工厂类

UML类图

示例代码

<?php interface Flyweight{ public function operation(); } class MyFlyweight implements Flyweight { protected $intrinsicState; function __construct($str) { $this->intrinsicState = $str; } public function operation() { echo 'MyFlyweight['.$this->intrinsicState.'] do operation. <br>'; } } class FlyweightFactory { protected static $flyweightPool; function __construct() { if (!isset(self::$flyweightPool)) { self::$flyweightPool = []; } } public function getFlyweight($str) { if (!array_key_exists($str,self::$flyweightPool)) { $fw = new MyFlyweight($str); self::$flyweightPool[$str] = $fw; return $fw; } else { echo "aready in the pool,use the exist one: <br>"; return self::$flyweightPool[$str]; } } } $factory = new FlyweightFactory(); $fw = $factory->getFlyweight('one'); $fw->operation(); $fw1 = $factory->getFlyweight('two'); $fw1->operation(); $fw2 = $factory->getFlyweight('one'); $fw2->operation();

享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。

代理模式

所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网络连接、内存中的大对象、文件或其它昂贵或无法复制的资源。

代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。

可能大家听得最多且最常用的就是VPN网络代理,或者代理服务器等。

角色

Subject: 抽象主题角色

Proxy: 代理主题角色

RealSubject: 真实主题角色

UML类图

示例代码

<?php interface Subject{ public function request(); } class RealSubject implements Subject { public function request() { echo "RealSubject::request <br>"; } } class Proxy implements Subject { protected $realSubject; function __construct() { $this->realSubject = new RealSubject(); } public function beforeRequest() { echo "Proxy::beforeRequest <br>"; } public function request() { $this->beforeRequest(); $this->realSubject->request(); $this->afterRequest(); } public function afterRequest() { echo "Proxy::afterRequest <br>"; } } $proxy = new Proxy(); $proxy->request();

下面将会介绍五种行为型模式。

命令模式

在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。

主要特点就是将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。

角色

Command: 抽象命令类

ConcreteCommand: 具体命令类

Invoker: 调用者

Receiver: 接收者

Client:客户类

UML类图

示例代码

<?php class Receiver { public function Action() { echo "Receiver->Action"; } } abstract class Command{ protected $receiver; function __construct(Receiver $receiver) { $this->receiver = $receiver; } abstract public function Execute(); } class MyCommand extends Command { function __construct(Receiver $receiver) { parent::__construct($receiver); } public function Execute() { $this->receiver->Action(); } } class Invoker { protected $command; function __construct(Command $command) { $this->command = $command; } public function Invoke() { $this->command->Execute(); } } $receiver = new Receiver(); $command = new MyCommand($receiver); $invoker = new Invoker($command); $invoker->Invoke();

中介者模式

《设计模式:可复用面向对象软件的基础》一书中对中介者模式定义:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

举个简单的例子,就比如大家平时喜欢用微信聊天,你发送的聊天内容需要通过微信服务器进行中间处理,然后下发给你的好友,微信服务器就是一个中介者。

角色

Mediator: 抽象中介者

ConcreteMediator: 具体中介者

Colleague: 抽象同事类

ConcreteColleague: 具体同事类

UML类图

示例代码

<?php abstract class Colleague{ protected $mediator; abstract public function sendMsg($who,$msg); abstract public function receiveMsg($msg); public function setMediator(Mediator $mediator){ $this->mediator = $mediator; } } class ColleagueA extends Colleague { public function sendMsg($toWho,$msg) { echo "Send Msg From ColleagueA To: ".$toWho . '<br>'; $this->mediator->opreation($toWho,$msg); } public function receiveMsg($msg) { echo "ColleagueA Receive Msg: ".$msg . '<br>'; } } class ColleagueB extends Colleague { public function sendMsg($toWho,$msg) { echo "Send Msg From ColleagueB To: ".$toWho . '<br>'; $this->mediator->opreation($toWho,$msg); } public function receiveMsg($msg) { echo "ColleagueB Receive Msg: ".$msg . '<br>'; } } abstract class Mediator{ abstract public function opreation($id,$message); abstract public function register($id,Colleague $colleague); } class MyMediator extends Mediator { protected static $colleagues; function __construct() { if (!isset(self::$colleagues)) { self::$colleagues = []; } } public function opreation($id,$message) { if (!array_key_exists($id,self::$colleagues)) { echo "colleague not found"; return; } $colleague = self::$colleagues[$id]; $colleague->receiveMsg($message); } public function register($id,Colleague $colleague) { if (!in_array($colleague, self::$colleagues)) { self::$colleagues[$id] = $colleague; } $colleague->setMediator($this); } } $colleagueA = new ColleagueA(); $colleagueB = new ColleagueB(); $mediator = new MyMediator(); $mediator->register(1,$colleagueA); $mediator->register(2,$colleagueB); $colleagueA->sendMsg(2,'hello admin'); $colleagueB->sendMsg(1,'shiyanlou');

中介者模式的两个主要作用:中转作用(结构性):通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事进行通信时,通过中介者即可。该中转作用属于中介者在结构上的支持。

协调作用(行为性):中介者可以更进一步的对同事之间的关系进行封装,同事可以一致地和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持。

观察者模式

在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

角色

Subject: 抽象目标类,一般至少提供三个接口:

添附(Attach):新增观察者到串炼内,以追踪目标对象的变化。解附(Detach):将已经存在的观察者从串炼中移除。通知(Notify):利用观察者所提供的更新函式来通知此目标已经产生变化。

ConcreteSubject: 具体目标,提供了观察者欲追踪的状态,也可设置目标状态

Observer: 抽象观察者,定义观察者的更新操作接口

ConcreteObserver: 具体观察者,实现抽象观察者的接口,做出自己的更新操作

UML类图

示例代码

<?php abstract class Obeserver{ abstract function update(Subject $sub); } abstract class Subject{ protected static $obeservers; function __construct() { if (!isset(self::$obeservers)) { self::$obeservers = []; } } public function attach(Obeserver $obeserver){ if (!in_array($obeserver, self::$obeservers)) { self::$obeservers[] = $obeserver; } } public function deattach(Obeserver $obeserver){ if (in_array($obeserver, self::$obeservers)) { $key = array_search($obeserver,self::$obeservers); unset(self::$obeservers[$key]); } } abstract public function setState($state); abstract public function getState(); public function notify() { foreach (self::$obeservers as $key => $value) { $value->update($this); } } } class MySubject extends Subject { protected $state; public function setState($state) { $this->state = $state; } public function getState() { return $this->state; } } class MyObeserver extends Obeserver { protected $obeserverName; function __construct($name) { $this->obeserverName = $name; } public function update(Subject $sub) { $state = $sub->getState(); echo "Update Obeserver[".$this->obeserverName.'] State: '.$state . '<br>'; } } $subject = new MySubject(); $one = new MyObeserver('one'); $two = new MyObeserver('two'); $subject->attach($one); $subject->attach($two); $subject->setState(1); $subject->notify(); echo "--------------------- <br>"; $subject->setState(2); $subject->deattach($two); $subject->notify();

主要作用:

当抽象个体有两个互相依赖的层面时。封装这些层面在单独的对象内将可允许程序员单独地去变更与重复使用这些对象,而不会产生两者之间交互的问题。当其中一个对象的变更会影响其他对象,却又不知道多少对象必须被同时变更时。当对象应该有能力通知其他对象,又不应该知道其他对象的实做细节时。

状态模式

状态模式:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

有时,一个对象的行为受其一个或多个具体的属性变化而变化,这样的属性也叫作状态,这样的的对象也叫作有状态的对象。

角色

Context: 环境类,维护一个ConcreteState子类的实例,这个实例定义当前状态;

State: 抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为;

ConcreteState: 具体状态类,每一个子类实现一个与Context的一个状态相关的行为。

UML类图

示例代码

<?php class Context{ protected $state; function __construct() { $this->state = StateA::getInstance(); } public function changeState(State $state) { $this->state = $state; } public function request() { $this->state->handle($this); } } abstract class State{ abstract function handle(Context $context); } class StateA extends State { private static $instance; private function __construct(){} private function __clone(){} public static function getInstance() { if (!isset(self::$instance)) { self::$instance = new self; } return self::$instance; } public function handle(Context $context) { echo "doing something in State A.\n done,change state to B <br>"; $context->changeState(StateB::getInstance()); } } class StateB extends State { private static $instance; private function __construct(){} private function __clone(){} public static function getInstance() { if (!isset(self::$instance)) { self::$instance = new self; } return self::$instance; } public function handle(Context $context) { echo "doing something in State B.\n done,change state to A <br>"; $context->changeState(StateA::getInstance()); } } $context = new Context(); $context->request(); $context->request(); $context->request(); $context->request();

策略模式

策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。

常见示例:常见的排序算法有快速排序,冒泡排序,归并排序,选择排序等,如果我们需要在一个算法类中提供这些算法,一个常见的解决方法就是在类中定义多个方法,每个方法定义一种具体的排序算法,然后使用 if...else...去判断到底是哪种算法,或者直接调用某个具体方法。这种方法是将算法的实现硬编码到类中,这样做最大的弊端就是算法类类非常臃肿,而且当需要增加或者更换一种新的排序方法时候,需要修改算法类的代码,同时也需要修改客户端调用处的代码。策略模式就是为了解决这列问题而设计的。

角色

Context: 环境类,使用一个ConcreteStrategy对象来配置;维护一个对Stategy对象的引用,同时,可以定义一个接口来让Stategy访问它的数据。

Strategy: 抽象策略类,定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法;

ConcreteStrategy: 具体策略类,实现 Strategy 接口的具体算法;

UML类图

示例代码

<?php abstract class Strategy{ abstract function use(); } class StrategyA extends Strategy { public function use() { echo "这是使用策略A的方法 <br>"; } } class StrategyB extends Strategy { public function use() { echo "这是使用策略B的方法 <br>"; } } class Context { protected $startegy; public function setStrategy(Strategy $startegy) { $this->startegy = $startegy; } public function use() { $this->startegy->use(); } } $context = new Context(); $startegyA = new StrategyA(); $startegyB = new StrategyB(); $context->setStrategy($startegyA); $context->use(); $context->setStrategy($startegyB); $context->use();
转载请注明原文地址: https://www.6miu.com/read-1471.html

最新回复(0)