前の記事では、構造パターンについてクラスとオブジェクトの構造について説明しました。全部で7種類あります。今回は行動パターンをご紹介します。
1. 行動パターンとは何ですか? behavioral Pattern:
私たち自身つまり、クラスとオブジェクトがどのような役割を果たし、その役割をどのように果たしていくかという問題です。
2. 動作パターンの種類
一般的に 3 つのカテゴリに分類されます: 一般的なパターン、既知のパターン、深いパターン
一般的なパターンには、テンプレート メソッド パターン、コマンド パターン、イテレータ パターン、オブザーバー モード、メディエーター モード、ステート モードが含まれます。 、責任の連鎖モード、戦略モード
使用する ' ' ' パターン (テンプレート):
操作でアルゴリズムのスケルトンを定義し、一部の実装手順をサブクラスに延期します。豆乳製造機と同じで、小豆を入れても黒豆を入れても出てくるのは豆乳です。
利点: 優れたスケーラビリティ、変更されていないコードをカプセル化し、可変コードを拡張します。
欠点: 柔軟性が低く、骨格部分を変更することができません。
適用シナリオ: 共通の特性を持つもののカテゴリーまたはグループ内。
コード実装
Phpコード
<?php /** * 优才网公开课示例代码 * * 模板方法模式 Template * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function output($string) { echo $string . "\n"; } class Request { public $token = ''; public function __construct() { $this->token = '0c6b7289f5334ed2b697dd461eaf9812'; } } class Response { public function render($content) { output(sprintf('response-render: %s', $content)); } public function redirect($uri) { output(sprintf('response-redirect: %s', $uri)); } public function json($data) { output(sprintf('response-data: %s', json_encode($data))); } } //父类,抽象类 abstract class Controller{ //封装了输入输出 protected $request; protected $response; //返回数据 protected $data = 'data'; public function __construct($request, $response){ $this->request = $request; $this->response = $response; } //执行请求函数,定义总体算法(template method),final防止被复写(不允许子类改变总体算法) public final function execute(){ $this->before(); if ($this->valid()){ $this->handleRequest(); } $this->after(); } //定义hook method before,做一些具体请求的前置处理 //非abstract方法,子类可以选择覆盖或不覆盖,默认什么都不做 protected function before(){ } //定义hook method valid,做请求的数据验证 //非abstract方法,子类可以选择覆盖或不覆盖,默认返回验证通过 protected function valid(){ return true; } //定义hook method handleRequest,处理请求 //定义为abstract方法,子类必须实现或也声明为抽象方法(由子类的子类负责实现) abstract function handleRequest(); //定义hook method after,做一些请求的后置处理 //非abstract方法,子类可以选择覆盖或不覆盖,默认直接输出数据 protected function after(){ $this->response->render($this->data); } } //子类1,实现父类开放的具体算法 class User extends Controller{ //覆盖before方法,实现具体算法,这是一个处理用户数据操作的控制器 //因此,我们选择在before里面判断用户是否已经登录了,这里简单判断下session数据 function before(){ if (emptyempty($_SESSION['auth'])){ //没登录就直接跳转了,不再执行后续的操作 $this->response->redirect("user/login.php"); } } //覆盖valid方法,这里我们验证用户提交数据中有没有带验证token function valid(){ if (isset($this->request->token)){ return true; } return false; } //覆盖handleRequest方法,必选,以为父类中声明了abstract了 function handleRequest(){ //做具体处理,一般根据参数执行不同的业务逻辑 } //这个类我们选择不覆盖after方法,使用默认处理方式 } //子类2,实现父类开放的具体算法 class Post extends Controller{ //这个类我们选择不覆盖before方法,使用默认处理方式 //这个类我们选择不覆盖valid方法,使用默认处理方式 //覆盖handleRequest方法,必选,以为父类中声明了abstract了 function handleRequest(){ //做具体处理,一般根据参数执行不同的业务逻辑 $this->data = array('title' => 'ucai'); } //覆盖after方法,使用json格式输出数据 function after(){ $this->response->json($this->data); } } class Client { public static 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. コマンドモード(コマンド):
動作リクエスタは動作実装者から分離されています。軍隊における「敬礼」と同じように、この命令を聞いた人は誰でも標準的な敬礼をするでしょう。 利点: 動作の追加と変更が簡単で、複数のコマンドを簡単に集約できます。 欠点: 特定のコマンド クラスが多すぎます。 応用シナリオ: 操作対象のオブジェクトに対して同じ操作を実行します。
コード実装
Phpコード
<?php /** * 优才网公开课示例代码 * * 命令模式 Command * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function output($string) { echo $string . "\n"; } class Document { private $name = ''; public function __construct($name) { $this->name = $name; } public function showText() { output(sprintf("showText: %s", $this->name)); } public function undo() { output(sprintf("undo-showText: %s", $this->name)); } } class Graphics { private $name = ''; public function __construct($name) { $this->name = $name; } public function drawCircle() { output(sprintf("drawCircle: %s", $this->name)); } public function undo() { output(sprintf("undo-drawCircle: %s", $this->name)); } } class Client { public static function test() { $document = new Document('A'); $graphics = new Graphics('B'); $document->showText(); $graphics->drawCircle(); $document->undo(); } } Client::test(); <?php /** * 优才网公开课示例代码 * * 命令模式 Command * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function output($string) { echo $string . "\n"; } interface Command { public function execute(); public function undo(); } class Document implements Command { private $name = ''; public function __construct($name) { $this->name = $name; } public function execute() { output(sprintf("showText: %s", $this->name)); } public function undo() { output(sprintf("undo-showText: %s", $this->name)); } } class Graphics implements Command { private $name = ''; public function __construct($name) { $this->name = $name; } public function execute() { output(sprintf("drawCircle: %s", $this->name)); } public function undo() { output(sprintf("undo-drawCircle: %s", $this->name)); } } class Client { public static 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();
<?php /** * 优才网公开课示例代码 * * 命令模式 Command * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function output($string) { echo $string . "\n"; } interface Command { public function execute(); public function undo(); } class Document { private $name = ''; public function __construct($name) { $this->name = $name; } public function showText() { output(sprintf("showText: %s", $this->name)); } public function undo() { output(sprintf("undo-showText: %s", $this->name)); } } class Graphics { private $name = ''; public function __construct($name) { $this->name = $name; } public function drawCircle() { output(sprintf("drawCircle: %s", $this->name)); } public function undo() { output(sprintf("undo-drawCircle: %s", $this->name)); } } class DocumentCommand implements Command { private $obj = ''; public function __construct(Document $document) { $this->obj = $document; } public function execute() { $this->obj->showText(); } public function undo() { $this->obj->undo(); } } class GraphicsCommand implements Command { private $obj = ''; public function __construct(Graphics $graphics) { $this->obj = $graphics; } public function execute() { $this->obj->drawCircle(); } public function undo() { $this->obj->undo(); } } class Client { public static 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(new Graphics('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):
内部構造を公開せずに集合オブジェクトの内容にアクセスします。二色玉の抽選と同じように、毎回7個の玉が振り出され、7個の玉以外の当選番号の組み合わせは振り切れない。
利点: さまざまな方法でコレクションを横断します。
欠点: 走査されるたびにコレクション全体が走査され、要素を個別に取り出すことはできません。
アプリケーションシナリオ: コレクション内のすべての要素を操作する必要があります。
コード実装
PHPコード
<?php /** * 优才网公开课示例代码 * * 迭代器模式 Iterator * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function output($string) { echo $string . "\n"; } class RecordIterator implements Iterator{ private $position = 0; //注意:被迭代对象属性是私有的 private $records = array(); public function __construct(Array $records) { $this->position = 0; $this->records = $records; } function rewind() { $this->position = 0; } function current() { return $this->records[$this->position]; } function key() { return $this->position; } function next() { ++$this->position; } function valid() { return isset($this->records[$this->position]); } } class PostListPager { protected $record = array(); protected $total = 0; protected $page = 0; protected $size = 0; public function __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; } public function getIterator() { return new RecordIterator($this->record); } public function getMaxPage() { $max = intval($this->total / $this->size); return $max; } public function getPrevPage() { return max($this->page - 1, 1); } public function getNextPage() { return min($this->page + 1, $this->getMaxPage()); } } class Client { public static 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();