摘要:代碼實現迭代器模式注意被迭代對象屬性是私有的觀察者模式又叫發布訂閱模式,當一個主體對象發生改變時,依賴它的多個觀察者對象都得到通知并自動更新響應。
在上一篇我們講了結構型模式,結構型模式是討論類和對象的結構的??偣灿?種。而今天我們來介紹一下行為型模式。
一、什么是行為型模式?
1、設計模式:
是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計的總結。就好像杯子,是被前人設計出來的,實現了儲存水的功能,解決了人們的喝水問題。大多數人喝水都用杯子。但是你不必自己再重做另外方法再做一種容器,而實現的也是同樣的功能,只要會用別人做出來的杯子喝水就能達到目的。但是杯子有很多中,實現喝水的方式也不同,比如茶水杯子,咖啡杯,啤酒杯子等等,要選擇適合自己的杯子,就如茶水要用帶過濾網的杯子,如果用不帶過濾網的會喝一嘴茶葉。合適的才是最好的。
總結出來設計模式的特性如下:
1.普遍性:經過前輩們的使用,大多人都實用的,總結提煉不斷的提升被普遍認為是實現某種事物的最有效的方法。
2.封裝性:既然是方法那我們就不用太關心細節是怎么實現的,而主要是學習怎么用這些方法模式,從而達到自己的目的。
3.面向對象性:指揮對象做事。把復雜問題簡單化。
4.最優性:要充分相信適合的就是最好的。
2、面向對象:
或許你對面向對象還有疑問?指揮對象做事,把復雜問題簡單化。那么我們就來舉個例子說明。比如我們去飯店吃飯,會叫服務員然后點菜,那我們就是指揮服務員做事,至于服務員怎么讓廚師做,廚師怎么做,這些我們都不管。我們只管是否能吃到我們叫到的菜。這個就是把復雜事情簡單化了。我們不用自己做菜,也不用知道菜怎么做,我們指揮服務員就行了,吃飯這件事就由復雜的做菜之類的變成吃這個簡單的事了。
3、行為型模式:
就是描述類和對象之間的通信和職責的。簡而言之,就是類和對象扮演什么角色,還有怎么扮演這個角色的問題。
二、行為型模式的種類
大體上分為三個大類:常見模式、已知模式、深度模式
常見模式包括: 模版方法模式命令模式 迭代器模式 觀察者模式 中介者模式 狀態式 職責鏈模式 策略模式
已知模式包括:備忘錄模式
深度模式包括:解釋器模式 訪問者模式
下面來介紹常見模式
? 常見模式
1、模版方法模式(Template):
定義一個操作中的算法骨架,而將一些實現步驟延遲到子類當中實現。就像一個豆漿機,不管放進去的是紅豆還是黑豆,出來的都是豆漿。
好處:擴展性好,封裝不變的代碼,擴展可變的代碼
弊端:靈活性差,不能改變骨架部分。
應用場景:一類或一組具有共性的事物中
代碼實現
/**
*
模板方法模式 Template
*/
function output($string) {
echo $string . "n";
}
class Request {
public$token = "";
publicfunction __construct() {
$this->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 methodbefore,做一些具體請求的前置處理
//非abstract方法,子類可以選擇覆蓋或不覆蓋,默認什么都不做
protectedfunction before(){
}
//定義hook methodvalid,做請求的數據驗證
//非abstract方法,子類可以選擇覆蓋或不覆蓋,默認返回驗證通過
protectedfunction valid(){
returntrue;
}
//定義hook methodhandleRequest,處理請求
//定義為abstract方法,子類必須實現或也聲明為抽象方法(由子類的子類負責實現)
abstractfunction handleRequest();
//定義hook methodafter,做一些請求的后置處理
//非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) :
行為請求者與行為實現者解耦。就像軍隊里的“敬禮”,不管是誰聽到這個命令都會做出標準的敬禮動作。
好處:便于添加和修改行為,便于聚合多個命令
弊端:造成過多具體的命令類
應用場景:對要操作的對象,進行的相同操作
代碼實現
/**
*
命令模式 Command
*/
function output($string) {
echo $string . "n";
}
class Document {
private$name = "";
public function __construct($name) {
$this->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();
/**
*
命令模式 Command
*/
function output($string) {
echo $string . "n";
}
interface Command {
publicfunction execute();
publicfunction undo();
}
class Document implements Command {
private$name = "";
publicfunction __construct($name) {
$this->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();
/**
*
命令模式 Command
*
*/
function output($string) {
echo $string . "n";
}
interface Command {
publicfunction execute();
publicfunction undo();
}
class Document {
private$name = "";
publicfunction __construct($name) {
$this->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):
訪問聚合對象內容而不暴露內部結構。就像一個雙色球彩票開獎一樣,每次都是搖出七個球,不能能搖不是七個球的中獎號碼組合。
好處:以不同方式遍歷一個集合
弊端:每次遍歷都是整個集合,不能多帶帶取出元素
應用場景:需要操作集合里的全部元素。
代碼實現:
/**
*
迭代器模式 Iterator
*/
function output($string) {
echo $string . "n";
}
class RecordIterator implements Iterator{
private$position = 0;
//注意:被迭代對象屬性是私有的
private$records = array();
publicfunction __construct(Array $records) {
$this->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):
又叫發布訂閱模式,當一個主體對象發生改變時,依賴它的多個觀察者對象都得到通知并自動更新響應。就像報社一樣,今天發布的消息只要是看這份報紙的人看到的都是同樣的內容。如果發布另一份報紙,也是一樣的。
好處:廣播式通信,范圍大,一呼百應,便于操作一個組團,“公有制”
弊端:不能多帶帶操作組團里的個體,不能實行按需分配
應用場景:操作多個對象,并操作相同。
代碼實現:
/**
優才網公開課示例代碼
*
觀察者模式 Observer
*/
function output($string) {
echo $string . "n";
}
//訂單數據對象簡單模擬,這個是實際需要被觀察的對象(Subject),但是我們將其獨立,然后
//通過構造方法傳入到我們模式中的Subject中,這樣使具體業務更加獨立
class Order{
//訂單號
private$id = "";
//用戶ID
private$userId = "";
//用戶名
private$userName = "";
//價格
private$price = "";
//下單時間
private$orderTime = "";
//訂單數據填充簡單模擬,實際應用中可能會讀取用戶表單輸入并處理
publicfunction __set($name, $value){
if(isset($this->$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}" );
//實際應用會調用郵件發送服務如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();
/**
*
觀察者模式 Observer
*/
function output($string) {
echo $string . "n";
}
//訂單數據對象簡單模擬,這個是實際需要被觀察的對象(Subject),但是我們將其獨立,然后
//通過構造方法傳入到我們模式中的Subject中,這樣使具體業務更加獨立
class Order{
//訂單號
private$id = "";
//用戶ID
private$userId = "";
//用戶名
private$userName = "";
//價格
private$price = "";
//下單時間
private$orderTime = "";
//訂單數據填充簡單模擬,實際應用中可能會讀取用戶表單輸入并處理
publicfunction __set($name, $value){
if(isset($this->$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}" );
}
}
//給用戶發送訂單確認郵件 (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();
5、中介者模式(Mediator):
用中介對象封裝一系列的對象交互,中介使各對象不需要顯式地相互引用。類似于郵局,郵寄者和收件者不用自己跑很遠路,通過郵局就可以。
好處:簡化了對象之間的關系,減少子類的生成
弊端:中介對象可能變得非常復雜,系統難以維護
應用場景:不需要顯示地建立交互
代碼實現:
/**
*
*/
function output($string) {
echo $string . "n";
}
abstract class Mediator { // 中介者角色
abstractpublic function send($message,$colleague);
}
abstract class Colleague { // 抽象對象
private$_mediator = null;
publicfunction __construct($mediator) {
$this->_mediator = $mediator;
}
publicfunction send($message) {
$this->_mediator->send($message,$this);
}
abstractpublic function notify($message);
}
class ConcreteMediator extends Mediator { // 具體中介者角色
private$_colleague1 = null;
private$_colleague2 = null;
publicfunction send($message,$colleague) {
if($colleague == $this->_colleague1) {
$this->_colleague1->notify($message);
} else{
$this->_colleague2->notify($message);
}
}
publicfunction set($colleague1,$colleague2) {
$this->_colleague1 = $colleague1;
$this->_colleague2 = $colleague2;
}
}
class Colleague1 extends Colleague { // 具體對象角色
publicfunction notify($message) {
output(sprintf("Colleague-1: %s", $message));
}
}
class Colleague2 extends Colleague { // 具體對象角色
publicfunction notify($message) {
output(sprintf("Colleague-2: %s", $message));
}
}
class Client {
publicstatic function test(){
//client
$objMediator = new ConcreteMediator();
$objC1= new Colleague1($objMediator);
$objC2= new Colleague2($objMediator);
$objMediator->set($objC1,$objC2);
$objC1->send("to c2 from c1");
$objC2->send("to c1 from c2");
}
}
Client::test();
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/22751.html
摘要:能夠協調調用者和被調用者,能夠在一定程度上降低系統的耦合性。特點低耦合性,獨立性好,安全性應用客戶訪問不到或者被訪問者希望隱藏自己,所以通過代理來訪問自己。 我們接著上面的幾種模式繼續講: 4、組合模式 將對象組合成樹形結構表示部分-整體的層次結構。 特點:靈活性強 應用:對象的部分-整體的層次結構,模糊組合對象和簡單對象處理問題 代碼實現 /** 組合模式* *///繼承模式clas...
摘要:我們分三篇文章來總結一下設計模式在中的應用,這是第一篇創建型模式。二提煉設計模式的幾個原則開閉原則模塊應對擴展開放,而對修改關閉。工廠模式實現定義一個用于創建對象的接口,讓子類決定實例化哪一個類。設計模式的第一部分,創建型模式就總結完了。 我們分三篇文章來總結一下設計模式在PHP中的應用,這是第一篇創建型模式。一、設計模式簡介 首先我們來認識一下什么是設計模式: 設計模式是一套被反復使...
摘要:最近開展了三次設計模式的公開課,現在來總結一下設計模式在中的應用,這是第一篇創建型模式之單例模式。不過因為不支持多線程所以不需要考慮這個問題了。 最近開展了三次設計模式的公開課,現在來總結一下設計模式在PHP中的應用,這是第一篇創建型模式之單例模式。 一、設計模式簡介 首先我們來認識一下什么是設計模式: 設計模式是一套被反復使用、容易被他人理解的、可靠的代碼設計經驗的總結。 設計模式不...
摘要:創建型模式主要有以下五種簡單工廠模式和工廠方法模式抽象工廠模式單例模式建造者模式原型模式在設計模式一書中將工廠模式分為兩類工廠方法模式與抽象工廠模式。 一、 設計模式(Design pattern)是什么 設計模式是一套被反復使用、多數人知曉、經過分類編目的代碼設計的經驗總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 二、 為什么會有設計模式 在軟件開發過...
閱讀 1523·2021-09-22 15:35
閱讀 2005·2021-09-14 18:04
閱讀 876·2019-08-30 15:55
閱讀 2449·2019-08-30 15:53
閱讀 2680·2019-08-30 12:45
閱讀 1203·2019-08-29 17:01
閱讀 2577·2019-08-29 15:30
閱讀 3514·2019-08-29 15:09