设计模式学习笔记(下)

    xiaoxiao2022-07-07  206

    <?php // 代理模式(Proxy)为其他对象提供一种代理以控制对这个对象的访问。使用代理模式创建代理对象,让代理对象控制目标对象的访问(目标对象可以是远程的对象、创建开销大的对象或需要安全控制的对象),并且可以在不改变目标对象的情况下添加一些额外的功能。 // 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。 // 经典例子就是网络代理,你想访问 Facebook 或者 Twitter ,如何绕过 GFW?找个代理 //抽象代理主题 abstract class Subject{ abstract public function action(); } //真正的访问端 class realSubject extends Subject { public function __construct(){ } public function action(){ echo '我是真实主题'; } } class proxySubject extends Subject{ private $realobj; public function __construct(){ } //使用action接口直接访问到真实主题,向用户屏蔽细节 public function action(){ $this->__before(); if(is_null($realobj)){ $this->realobj=new realSubject(); } $this->realobj->action(); $this->__after(); } private function __before(){ echo '在使用代理前'; } private function __after(){ echo '在使用代理后'; } } $real=new proxySubject(); $real->action(); <?php // 命令模式:在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式。 // 角色分析: // 抽象命令:定义命令的接口,声明执行的方法。 // 具体命令:命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。 // 命令接收者:接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。 // 控制者:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。 abstract class Command{ protected $rece; public abstract function Excute(); } //定义接受者行为(实际工程时候,接受者可以写成队列) class Rece{ public function action(){ echo '我正在执行请求'; } } //具体命令实例,命令接受者执行行为 class ConCommand extends Command{ public function __construct(Rece $obj){ $this->rece=$obj; } public function Excute(){ $this->rece->action(); } } //请求执行类 class Invoker{ private $Command; public function __construct(Command $obj){ $this->Command=$obj; } public function ExeCommand(){//看出请求执行类实际上直接调用了接收者 $this->Command->Excute(); } } $Invoker=new Invoker(new ConCommand(new Rece)); $Invoker->ExeCommand(); <?php //备忘录模式又叫做快照模式(Snapshot)或 Token 模式,备忘录模式的用意是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样就可以在合适的时候将该对象恢复到原先保存的状态。 // 我们在编程的时候,经常需要保存对象的中间状态,当需要的时候,可以恢复到这个状态。比如,我们使用Eclipse进行编程时,假如编写失误(例如不小心误删除了几行代码),我们希望返回删除前的状态,便可以使用Ctrl+Z来进行返回。这时我们便可以使用备忘录模式来实现。 // 备忘录模式所涉及的角色有三个:备忘录(Memento)角色、发起人(Originator)角色、负责人(Caretaker)角色。 //这三个角色的职责分别是: //发起人:记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘录数据。 //备忘录:负责存储发起人对象的内部状态,在需要的时候提供发起人需要的内部状态。 //管理角色:对备忘录进行管理,保存和提供备忘录。 //发起人,可以创建备忘录来记录当前时刻它内部状态,并可使用备忘录恢复 class Originator{ private $nowState; public function __construct($information){ $this->nowState=$information; } public function createMemento(){ return new Memento($this->nowState); } //向管理人索要备忘录,并从备忘录中获得之前的状态。 public function setMemento(Memento $obj){ $this->nowState=$obj->returnState(); } public function changeSaveState(Memento $obj,$nowState){//定义修改的状态 $obj->changeSaveState($nowState); } public function display(){ echo '现在状态是:'.$this->nowState.'<br>'; } } //备忘录类,存储Originator,并防止除了Originator以外的类访问 class Memento{ private $state;// 需要保存的状态or信息 public function __construct($information){ $this->state=$information; } public function changeSaveState($nowState){ $this->state=$nowState; } public function returnState(){ return $this->state; } } //管理者,负责将备忘录传递给要恢复备份的对象,也就是说,发起人创建备忘录给管理人管理,当要进行恢复时,向管理人索要备忘录进行恢复 class Caretaker{ private $Memento; public function __construct(Memento $obj){ $this->Memento=$obj; } public function returnMemento(){ return $this->Memento; } } $Originator=new Originator('良好'); $Memento=$Originator->createMemento();//假设创建的备忘录只有一本 $Caretaker=new Caretaker($Memento); $Originator->display();//创建备份并打印当前状态 $Originator->changeSaveState($Memento,'很差'); $Originator->display(); $Originator->setMemento($Caretaker->returnMemento()); $Originator->display(); <?php //模板模式准备一个抽象类,将部分逻辑以具体方法以及具体构造形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。 //模板模式 abstract class AbstractClass{ //定义子类要实现的行为,在这里抽象。 public abstract function Operat1(); public abstract function Operat2(); //定义大体逻辑框架 public function TemplateMethod(){ $this->Operat1(); $this->Operat2(); echo '我是大体的逻辑框架'; } } class ConcreteClassA extends AbstractClass{ public function Operat1(){ echo '我是子类A具体的算法1'; } public function Operat2(){ echo '我是子类A具体的算法2'; } } class ConcreteClassB extends AbstractClass{ public function Operat1(){ echo '我是子类b具体的算法1'; } public function Operat2(){ echo '我是子类b具体的算法2'; } } $b=new ConcreteClassA(); $b->TemplateMethod(); ?> <?php //状态模式 //状态模式当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。 // 上下文环境(Context):它定义了客户程序需要的接口并维护一个具体状态角色的实例,将与状态相关的操作委托给当前的具体状态对象来处理。 // 抽象状态(State):定义一个接口以封装使用上下文环境的的一个特定状态相关的行为。 // 具体状态(ConcreteState):实现抽象状态定义的接口。 class Context{ private $State; public function __construct(State $obj){ $this->State=$obj; } public function Request(){ $this->State->Handle($this); } public function setState(State $obj){ $this->State=$obj; } } //抽象状态类,与Context的行为相关,并且行为根据状态发生改变的条件判断语句过于复杂 abstract class State{ public abstract function Handle(Context $obj); } class ConcreteStateA extends State{ public function __construct(){ echo '我是状态A'.'<br>'; } //context状态不断发生变化,当前是A则改变到状态B public function Handle(Context $obj){ $obj->setState( new ConcreteStateB()); } } class ConcreteStateB extends State{ public function __construct(){ echo '我是状态B'.'<br>'; } //context状态不断发生变化,当前是A则改变到状态B public function Handle(Context $obj){ //这里可以加条件分支判断语句来决定实例某种状态。 $obj->setState( new ConcreteStateA()); } } $context = new Context(new ConcreteStateA); $context->Request(); $context->Request(); $context->Request(); $context->Request(); ?> <?php //行为模式(Behavioral Patterns)(11种):用于方法实现以及对应算法的设计模式,同时也是最复杂的设计模式。行为设计模式不仅仅用于定义类的函数行为,同时也用于不同类之间的协议、通信。 //策略模式 //定义一个支持所有算法的公共抽象接口 abstract class Strategy{ public abstract function algInterface(); } class ConcreteStrategyA extends Strategy{ public function algInterface(){ echo '这是算法/策略A'; } } class ConcreteStrategyB extends Strategy{ public function algInterface(){ echo '这是算法/策略B'; } } class Context { private $obj; public function __construct(Strategy $obj){ $this->obj= $obj; } public function ContextalgInterface(){ $this->obj->algInterface(); } } $context = new Context(new ConcreteStrategyB); $context->ContextalgInterface(); ?> <?php //职责链模式 //这种模式有另一种称呼:控制链模式。它主要由一系列对于某些命令的处理器构成,每个查询会在处理器构成的责任链中传递,在每个交汇点由处理器判断是否需要对它们进行响应与处理。每次的处理程序会在有处理器处理这些请求时暂停。 abstract class Handle{ protected $successor; public function setSuccessor(Handle $obj){//用来定义后继节点 $this->successor=$obj; } public abstract function HandleRequest(int $request);//设置节点有效处理范围 } class ConHandle1 extends Handle{ public function HandleRequest(int $request){ if($request>1&&$request<10) echo '我是节点1,我在处理当前请求'.'<br>'; else $this->successor->HandleRequest($request); } } class ConHandle2 extends Handle{ public function HandleRequest(int $request){ if($request>10&&$request<20) echo '我是节点2,我在处理当前请求'.'<br>'; } } $Handle1= new ConHandle1(); $Handle2= new ConHandle2(); $Handle1->setSuccessor($Handle2); $arr=array(1,2,3,6,17,16); foreach ($arr as $key => $value) { $Handle1->HandleRequest($value); } ?> <?php //观察者模式 //某个对象可以被设置为是可观察的,只要通过某种方式允许其他对象注册为观察者。每当被观察的对象改变时,会发送信息给观察者。 abstract class Subject{ private $arr=array();//存放观察者对象(数组) public function addObser(Observer $obj){ $this->arr[]=$obj; } public function removeObser(Observer $obj){ foreach ($this->arr as $key => $value) { if($value == $obj){ unset($this->arr[$key]); } } } //将变动消息通知给观察者 public function Notify(){ foreach ($this->arr as $key => $value) { $value->update(); } } } //观察者抽象类 abstract class Observer{ public function update(){} } class ConcreteSubject extends Subject{ private $SubjectState; public function __construct($state){ $this->SubjectState=$state; } //设置观察者状态 public function setState(){ return $this->SubjectState; } public function changeState($Statevalue){ $this->SubjectState=$Statevalue; } } class ConCreteObserver extends Observer{ private $Observername; private $ConcreteSubject;//保存主题,以便接受主题状态信息 public function __construct($name,Subject $obj ){ $this->ConcreteSubject=$obj; $this->Observername=$name; } //获得自己当前状态 public function update(){ $value=$this->ConcreteSubject->setState(); echo '观察者: '.$this->Observername.'的状态是'.$value.'<br>'; } } $subject = new ConcreteSubject('良好'); $subject->addObser(new ConCreteObserver('观察者A',$subject)); //$subject->Notify(); $subject->addObser(new ConCreteObserver('观察者A',$subject)); //$subject->removeObser(new ConCreteObserver('观察者A',$subject)); $subject->changeState('愤怒'); $subject->addObser(new ConCreteObserver('观察者B',$subject)); $subject->Notify();//主题去通知观察者。 ?> <?php // 给定一个语言, 定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。 // 角色: // 环境角色(PlayContent):定义解释规则的全局信息。 // 抽象解释器(Empress):定义了部分解释具体实现,封装了一些由具体解释器实现的接口。 // 具体解释器(MusicNote):实现抽象解释器的接口,进行具体的解释执行。 <?php class Expression { //抽象表示 function interpreter($str) { return $str; } } class ExpressionNum extends Expression { //表示数字 function interpreter($str) { switch($str) { case "0": return "零"; case "1": return "一"; case "2": return "二"; case "3": return "三"; case "4": return "四"; case "5": return "五"; case "6": return "六"; case "7": return "七"; case "8": return "八"; case "9": return "九"; } } } class ExpressionCharater extends Expression { //表示字符 function interpreter($str) { return strtoupper($str); } } class Interpreter { //解释器 function execute($string) { $expression = null; for($i = 0;$i<strlen($string);$i++) { $temp = $string[$i]; switch(true) { case is_numeric($temp): $expression = new ExpressionNum(); break; default: $expression = new ExpressionCharater(); } echo $expression->interpreter($temp); echo "<br>"; } } } //client $obj = new Interpreter(); $obj->execute("123s45abc"); ?> <?php // 访问者模式是一种行为型模式,访问者表示一个作用于某对象结构中各元素的操作。它可以在不修改各元素类的前提下定义作用于这些元素的新操作,即动态的增加具体访问者角色。 // 访问者模式利用了双重分派。先将访问者传入元素对象的Accept方法中,然后元素对象再将自己传入访问者,之后访问者执行元素的相应方法。 // 主要角色 // 抽象访问者角色(Visitor):为该对象结构(ObjectStructure)中的每一个具体元素提供一个访问操作接口。该操作接口的名字和参数标识了 要访问的具体元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它。 // 具体访问者角色(ConcreteVisitor):实现抽象访问者角色接口中针对各个具体元素角色声明的操作。 // 抽象节点(Node)角色:该接口定义一个accept操作接受具体的访问者。 // 具体节点(Node)角色:实现抽象节点角色中的accept操作。 // 对象结构角色(ObjectStructure):这是使用访问者模式必备的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个复合(组合模式)或是一个集合,如一个列表或一个无序集合(在PHP中我们使用数组代替,因为PHP中的数组本来就是一个可以放置任何类型数据的集合) // 适用性 // 访问者模式多用在聚集类型多样的情况下。在普通的形式下必须判断每个元素是属于什么类型然后进行相应的操作,从而诞生出冗长的条件转移语句。而访问者模式则可以比较好的解决这个问题。对每个元素统一调用element−>accept(vistor)即可。 // 访问者模式多用于被访问的类结构比较稳定的情况下,即不会随便添加子类。访问者模式允许被访问结构添加新的方法。 interface Visitor { // 抽象访问者角色 public function visitConcreteElementA(ConcreteElementA $elementA); public function visitConcreteElementB(concreteElementB $elementB); } interface Element { // 抽象节点角色 public function accept(Visitor $visitor); } class ConcreteVisitor1 implements Visitor { // 具体的访问者1 public function visitConcreteElementA(ConcreteElementA $elementA) {} public function visitConcreteElementB(ConcreteElementB $elementB) {} } class ConcreteVisitor2 implements Visitor { // 具体的访问者2 public function visitConcreteElementA(ConcreteElementA $elementA) {} public function visitConcreteElementB(ConcreteElementB $elementB) {} } class ConcreteElementA implements Element { // 具体元素A private $_name; public function __construct($name) { $this->_name = $name; } public function getName() { return $this->_name; } public function accept(Visitor $visitor) { // 接受访问者调用它针对该元素的新方法 $visitor->visitConcreteElementA($this); } } class ConcreteElementB implements Element { // 具体元素B private $_name; public function __construct($name) { $this->_name = $name;} public function getName() { return $this->_name; } public function accept(Visitor $visitor) { // 接受访问者调用它针对该元素的新方法 $visitor->visitConcreteElementB($this); } } class ObjectStructure { // 对象结构 即元素的集合 private $_collection; public function __construct() { $this->_collection = array(); } public function attach(Element $element) { return array_push($this->_collection, $element); } public function detach(Element $element) { $index = array_search($element, $this->_collection); if ($index !== FALSE) { unset($this->_collection[$index]); } return $index; } public function accept(Visitor $visitor) { foreach ($this->_collection as $element) { $element->accept($visitor); } } } // client $elementA = new ConcreteElementA("ElementA"); $elementB = new ConcreteElementB("ElementB"); $elementA2 = new ConcreteElementB("ElementA2"); $visitor1 = new ConcreteVisitor1(); $visitor2 = new ConcreteVisitor2(); $os = new ObjectStructure(); $os->attach($elementA); $os->attach($elementB); $os->attach($elementA2); $os->detach($elementA); $os->accept($visitor1); $os->accept($visitor2); ?> <?php //迭代器模式已经被很多语言内置了 //foreach()就是专门实现迭代功能的 //迭代器模式 (Iterator),又叫做游标(Cursor)模式。提供一种方法访问一个容器(Container)对象中各个元素,而又不需暴露该对象的内部细节。 // 当你需要访问一个聚合对象,而且不管这些对象是什么都需要遍历的时候,就应该考虑使用迭代器模式。另外,当需要对聚集有多种方式遍历时,可以考虑去使用迭代器模式。迭代器模式为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口。 // php标准库(SPL)中提供了迭代器接口 Iterator,要实现迭代器模式,实现该接口即可。 //PHP Iterator接口的作用是允许对象以自己的方式迭代内部的数据,从而使它可以被循环访问 class sample implements Iterator { private $_items ; public function __construct(&$data) { $this->_items = $data; } public function current() { return current($this->_items); } public function next() { next($this->_items); } public function key() { return key($this->_items); } public function rewind() { reset($this->_items); } public function valid() { return ($this->current() !== FALSE); } } // client $data = array(1, 2, 3, 4, 5); $sa = new sample($data); foreach ($sa AS $key => $row) { echo $key, ' ', $row, '<br />'; }

     

    最新回复(0)