热门IT资讯网

Php设计模式(三):行为型模式 part1

发表于:2024-11-26 作者:热门IT资讯网编辑
编辑最后更新 2024年11月26日,在上一篇我们讲了结构型模式,结构型模式是讨论类和对象的结构的。总共有7种。而今天我们来介绍一下行为型模式。一、什么是行为型模式?行为型模式:就是描述类和对象之间的通信和职责的。简而言之,就是类和对象扮

在上一篇我们讲了结构型模式,结构型模式是讨论类和对象的结构的。总共有7种。而今天我们来介绍一下行为型模式。


一、什么是行为型模式?

行为型模式:

就是描述类和对象之间的通信和职责的。简而言之,就是类和对象扮演什么角色,还有怎么扮演这个角色的问题。


二、行为型模式的种类

大体上分为三个大类:常见模式、已知模式、深度模式

常见模式包括: 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、状态模式、职责链模式、策略模式;

已知模式包括:备忘录模式

深度模式包括:解释器模式、访问者模式

下面来介绍常见模式

常见模式

1、模版方法模式(Template):

定义一个操作中的算法骨架,而将一些实现步骤延迟到子类当中实现。就像一个豆浆机,不管放进去的是红豆还是黑豆,出来的都是豆浆。

好处:扩展性好,封装不变的代码,扩展可变的代码。

弊端:灵活性差,不能改变骨架部分。

应用场景:一类或一组具有共性的事物中

代码实现


token    ='0c6b7289f5334ed2b697dd461eaf9812';    } } class Response {     publicfunction render($content) {       output(sprintf('response-render: %s', $content));    }     publicfunction redirect($uri) {       output(sprintf('response-redirect: %s', $uri));    }     publicfunction json($data) {       output(sprintf('response-data: %s', json_encode($data)));    } }  //父类,抽象类abstract class Controller{    //封装了输入输出    protected$request;    protected$response;     //返回数据    protected$data = 'data';     publicfunction __construct($request, $response){       $this->request = $request;       $this->response = $response;    }     //执行请求函数,定义总体算法(template method),final防止被复写(不允许子类改变总体算法)    publicfinal function execute(){       $this->before();        if($this->valid()){           $this->handleRequest();        }       $this->after();    }     //定义hook method before,做一些具体请求的前置处理    //非abstract方法,子类可以选择覆盖或不覆盖,默认什么都不做    protectedfunction before(){     }     //定义hook method valid,做请求的数据验证    //非abstract方法,子类可以选择覆盖或不覆盖,默认返回验证通过    protectedfunction valid(){        returntrue;    }     //定义hook method handleRequest,处理请求    //定义为abstract方法,子类必须实现或也声明为抽象方法(由子类的子类负责实现)    abstractfunction handleRequest();     //定义hook method after,做一些请求的后置处理    //非abstract方法,子类可以选择覆盖或不覆盖,默认直接输出数据    protectedfunction after(){       $this->response->render($this->data);    }} //子类1,实现父类开放的具体算法class User extends Controller{    //覆盖before方法,实现具体算法,这是一个处理用户数据操作的控制器    //因此,我们选择在before里面判断用户是否已经登录了,这里简单判断下session数据    functionbefore(){        if(empty($_SESSION['auth'])){            //没登录就直接跳转了,不再执行后续的操作           $this->response->redirect("user/login.php");        }    }     //覆盖valid方法,这里我们验证用户提交数据中有没有带验证token    functionvalid(){        if(isset($this->request->token)){           return true;        }        returnfalse;    }     //覆盖handleRequest方法,必选,以为父类中声明了abstract了    functionhandleRequest(){        //做具体处理,一般根据参数执行不同的业务逻辑    }     //这个类我们选择不覆盖after方法,使用默认处理方式} //子类2,实现父类开放的具体算法class Post extends Controller{    //这个类我们选择不覆盖before方法,使用默认处理方式     //这个类我们选择不覆盖valid方法,使用默认处理方式     //覆盖handleRequest方法,必选,以为父类中声明了abstract了    functionhandleRequest(){        //做具体处理,一般根据参数执行不同的业务逻辑       $this->data = array('title' => 'ucai');    }     //覆盖after方法,使用json格式输出数据    functionafter(){       $this->response->json($this->data);    }}   class Client {           publicstatic function test(){          $request        = new Request();       $response       = new Response();         //最终调用        $user= new User($request, $response);       $user->execute();          //最终调用        $post= new Post($request, $response);       $post->execute();     }        }    Client::test();



2、命令模式(Command) :

行为请求者与行为实现者解耦。就像军队里的"敬礼",不管是谁听到这个命令都会做出标准的敬礼动作。

好处:便于添加和修改行为,便于聚合多个命令

弊端:造成过多具体的命令类

应用场景:对要操作的对象,进行的相同操作

代码实现


name = $name;    }     publicfunction showText() {       output(sprintf("showText: %s", $this->name));    }     publicfunction undo() {       output(sprintf("undo-showText: %s", $this->name));    } } class Graphics {     private$name = '';     publicfunction __construct($name) {       $this->name = $name;    }     publicfunction drawCircle() {       output(sprintf("drawCircle: %s", $this->name));    }     publicfunction undo() {       output(sprintf("undo-drawCircle: %s", $this->name));    } } class Client {        publicstatic function test() {        $document       = newDocument('A');       $graphics       = newGraphics('B');        $document->showText();       $graphics->drawCircle();        $document->undo();     } } Client::test();  name = $name;    }     publicfunction execute() {       output(sprintf("showText: %s", $this->name));    }     publicfunction undo() {       output(sprintf("undo-showText: %s", $this->name));    } } class Graphics implements Command {     private$name = '';     publicfunction __construct($name) {       $this->name = $name;    }     publicfunction execute() {       output(sprintf("drawCircle: %s", $this->name));    }     publicfunction undo() {       output(sprintf("undo-drawCircle: %s", $this->name));    } } class Client {        publicstatic function test() {        $array          = array();        array_push($array, new Document('A'));       array_push($array, new Document('B'));       array_push($array, new Graphics('C'));       array_push($array, new Graphics('D'));               foreach ($array as $command) {           $command->execute();        }         $top            = array_pop($array);       $top->undo();     } } Client::test();  name = $name;    }     publicfunction showText() {       output(sprintf("showText: %s", $this->name));    }     publicfunction undo() {       output(sprintf("undo-showText: %s", $this->name));    } } class Graphics {     private$name = '';     publicfunction __construct($name) {       $this->name = $name;    }     publicfunction drawCircle() {       output(sprintf("drawCircle: %s", $this->name));    }     publicfunction undo() {       output(sprintf("undo-drawCircle: %s", $this->name));    } } class DocumentCommand implements Command {     private$obj = '';     publicfunction __construct(Document $document) {       $this->obj = $document;    }     publicfunction execute() {       $this->obj->showText();    }     publicfunction undo() {       $this->obj->undo();    } } class GraphicsCommand implements Command {     private$obj = '';     publicfunction __construct(Graphics $graphics) {       $this->obj = $graphics;    }     publicfunction execute() {       $this->obj->drawCircle();    }     publicfunction undo() {       $this->obj->undo();    } }  class Client {        publicstatic function test() {        $array          = array();        array_push($array, new DocumentCommand(new Document('A')));       array_push($array, new DocumentCommand(new Document('B')));        array_push($array, new GraphicsCommand(newGraphics('C')));       array_push($array, new GraphicsCommand(new Graphics('D')));               foreach ($array as $command) {           $command->execute();        }        $top            = array_pop($array);       $top->undo();     } } Client::test();


3、迭代器模式(Iterator):

访问聚合对象内容而不暴露内部结构。就像一个双色球×××开奖一样,每次都是摇出七个球,不能能摇不是七个球的中奖号码组合。

好处:以不同方式遍历一个集合

弊端:每次遍历都是整个集合,不能单独取出元素

应用场景:需要操作集合里的全部元素。

代码实现:


position = 0;       $this->records = $records;    }     functionrewind() {       $this->position = 0;    }     functioncurrent() {        return$this->records[$this->position];    }     functionkey() {        return$this->position;    }     functionnext() {       ++$this->position;    }     functionvalid() {        returnisset($this->records[$this->position]);    }} class PostListPager {     protected$record   = array();    protected$total    = 0;    protected$page     = 0;    protected$size     = 0;     publicfunction __construct($category, $page, $size) {        $this->page     = $page;       $this->size     = $size;         //query db        $total          = 28;       $this->total    = $total;        $record     = array(                        0 => array('id'=> '1'),                        1 => array('id'=> '2'),                        2 => array('id'=> '3'),                        3 => array('id'=> '4'),                    );         //       $this->record   = $record;     }     publicfunction getIterator() {       return  newRecordIterator($this->record);    }     publicfunction getMaxPage() {       $max    = intval($this->total /$this->size);        return  $max;    }     publicfunction getPrevPage() {       return  max($this->page - 1,1);    }     publicfunction getNextPage() {       return  min($this->page + 1,$this->getMaxPage());    } } class Client {           publicstatic function test(){          $pager      = new PostListPager(1,2, 4);        foreach ($pager->getIterator() as $key => $val) {           output(sprintf('Key[%d],Val[%s]', $key, json_encode($val)));        }        output(sprintf('MaxPage[%d]', $pager->getMaxPage()));       output(sprintf('Prev[%d]', $pager->getPrevPage()));       output(sprintf('Next[%d]', $pager->getNextPage()));        $iterator       =$pager->getIterator();       while($iterator->valid()){           print_r($iterator->current());           $iterator->next();        }       $iterator->rewind();     }        }    Client::test();


4、观察者模式(Observer):

又叫发布订阅模式,当一个主体对象发生改变时,依赖它的多个观察者对象都得到通知并自动更新响应。就像报社一样,今天发布的消息只要是看这份报纸的人看到的都是同样的内容。如果发布另一份报纸,也是一样的。

好处:广播式通信,范围大,一呼百应,便于操作一个组团,"公有制"

弊端:不能单独操作组团里的个体,不能实行按需分配

应用场景:操作多个对象,并操作相同。

代码实现:


$name)){           $this->$name = $value;        }    }     //获取订单属性    public function__get($name){        if(isset($this->$name)){           return $this->$name;        }        return"";    }} //假设的DB类,便于测试,实际会存入真实数据库class FakeDB{    publicfunction save($data){        returntrue;    }}  class Client {        publicstatic function test() {         //初始化一个订单数据        $order= new Order();       $order->id = 1001;       $order->userId = 9527;       $order->userName = "God";       $order->price = 20.0;       $order->orderTime = time();         //向数据库保存订单        $db =new FakeDB();       $result = $db->save($order);        if($result){             //实际应用可能会写到日志文件中,这里直接输出           output( "[OrderId:{$order->id}] [UseId:{$order->userId}][Price:{$order->price}]" );             //实际应用会调用邮件发送服务如sendmail,这里直接输出           output( "Dear {$order->userName}: Your order {$order->id} wasconfirmed!" );             //实际应用会调用邮件发送服务如sendmail,这里直接输出           output( "Dear Manager: User{$order->userName}(ID:{$order->userId}) submitted a new order {$order->id},please handle it ASAP!" );         }     } } Client::test();  $name)){           $this->$name = $value;        }    }     //获取订单属性    publicfunction __get($name){        if(isset($this->$name)){           return $this->$name;        }        return"";    }} //被观察者, 负责维护观察者并在变化发生是通知观察者class OrderSubject implements SplSubject {    private$observers;    private$order;     publicfunction __construct(Order $order) {       $this->observers = new SplObjectStorage();       $this->order = $order;    }     //增加一个观察者    publicfunction attach(SplObserver $observer) {       $this->observers->attach($observer);    }     //移除一个观察者    publicfunction detach(SplObserver $observer) {        $this->observers->detach($observer);    }     //通知所有观察者    publicfunction notify() {       foreach ($this->observers as $observer) {           $observer->update($this);        }    }     //返回主体对象的具体实现,供观察者调用    publicfunction getOrder() {        return$this->order;    }} //记录业务数据日志 (ActionLogObserver),实际可能还要抽象一层以处理不同的Action(业务操作),这里省略class ActionLogObserver implements SplObserver{    publicfunction update(SplSubject $subject) {        $order = $subject->getOrder();         //实际应用可能会写到日志文件中,这里直接输出        output( "[OrderId:{$order->id}] [UseId:{$order->userId}][Price:{$order->price}]" );    }} //给用户发送订单确认邮件 (UserMailObserver)class UserMailObserver implements SplObserver{    publicfunction update(SplSubject $subject) {         $order = $subject->getOrder();         //实际应用会调用邮件发送服务如sendmail,这里直接输出        output( "Dear {$order->userName}: Your order {$order->id} wasconfirmed!" );    }} //给管理人员发订单处理通知邮件 (AdminMailObserver)class AdminMailObserver implements SplObserver{    publicfunction update(SplSubject $subject) {        $order = $subject->getOrder();         //实际应用会调用邮件发送服务如sendmail,这里直接输出        output( "Dear Manager: User{$order->userName}(ID:{$order->userId}) submitted a new order{$order->id}, please handle it ASAP!" );    }} //假设的DB类,便于测试,实际会存入真实数据库class FakeDB{    publicfunction save($data){        returntrue;    }}  class Client {        publicstatic function test() {         //初始化一个订单数据        $order= new Order();       $order->id = 1001;       $order->userId = 9527;       $order->userName = "God";       $order->price = 20.0;       $order->orderTime = time();         //绑定观察者       $subject = new OrderSubject($order);       $actionLogObserver = new ActionLogObserver();        $userMailObserver = newUserMailObserver();       $adminMailObserver = new AdminMailObserver();       $subject->attach($actionLogObserver);       $subject->attach($userMailObserver);       $subject->attach($adminMailObserver);        //向数据库保存订单        $db =new FakeDB();       $result = $db->save($order);        if($result){            //通知观察者           $subject->notify();        }     } } Client::test();


欲知后事如何,且听下回分解~·~

0