PHP_設計模式

什麼是設計模式

在軟件開發過程當中,常常出現的經典場景的典型解決方案,稱爲設計模式php

如何學習設計模式html

典型場景 --> 典型問題 --> 典型解決辦法java

多態

用來消除邏輯語句.mysql

多態(ploymorphism)是一個生物學上的概念,指同一特種的多種表現形態.sql

在面向對象中,指某種對象實例的不一樣表現形態.數據庫

<?php

abstract class Tiger {
  public abstract function climb();
}

class XTiger extends Tiger {
  public function climb() {
    echo 'Drop' , '<br/>';
  }
}

class MTiger extends Tiger {
  public function climb() {
    echo 'Up' , '<br/>';
  }
}

class Cat {
  public function climb() {
    echo 'Fly';
  }
}

class Client {
  public static function call(Tiger $animal) { // 參數限定不嚴格,能夠更加靈活, 能夠傳遞一個父類類型,就能夠有不一樣的子類形態
    $animal->climb();
  }
}

Client::call(new XTiger());
Client::call(new MTiger());
Client::call(new Cat());

?>

在23種設計模式中,能夠有些模式能夠天然消除的.json

面向接口開發

減小new 的操做.設計模式

熟悉概念:安全

調用端的概念
客戶端(Client)的概念服務器

例如:在Java中,寫了一堆類,最終打成一個包。調用端能夠把包引入,而後使用類中定義的方法,在開發過程當中可使用查看裏面的方法。

假設:開發中引入的是sdk,都不讓看。如何調用,必須開放一些接口。存在面向接口開發

接口:共同的規則

面向接口開發

<?php


// 共同接口
// 服務端打包
interface DB {
  function conn();
}


// 服務端開發(不知道將會被誰調用)
class DbMysql implements DB {
  public function conn() {
    echo 'conn mysql <br/>';
  }
}

class DbSqlite implements DB {
  public function conn() {
    echo 'conn sqlite  <br/>';
  }
}


// ***客戶端**** (看不到DbMysql,DbSqlite的內部實現細節)
// 只知道,上述兩個類實現了db接口

$db = new DbMysql();
$db->conn();

$db = new DbSqlite();
$db->conn();

// 不管是開發者,仍是調用者都是爲接口負責

簡單工廠模式

模式的做用:
發生鏈接的雙方,知道的越少越好.

在面向對象設計法則中,重要的開閉原則:對於修改是封閉的,對於擴展是開放的.

<?php


// 共同接口
// 服務端打包
interface DB {
  function conn();
}


// 服務端開發(不知道將會被誰調用)
class DbMysql implements DB {
  public function conn() {
    echo 'conn mysql <br/>';
  }
}

class DbSqlite implements DB {
  public function conn() {
    echo 'conn sqlite  <br/>';
  }
}


// 簡單工廠
class Factory {
  public static function createDB($type) {
    if ($type == 'mysql') {
      return new DbMysql();
    } else if ($type == 'sqlite') {
      return new DbSqlite();
    } else {
      throw new Exception('Error db type', 1);
    }
  }
}


// 客戶端不知道服務端到底有哪些類名,
// 只知道對方開放了一個Factory::createDB方法.
// 靜態方法容許傳遞數據庫名稱

$msqyl = Factory::createDB('mysql');
$msqyl->conn();

$sqlit  = Factory::createDB('sqlite');
$sqlit->conn();


// 若是增長oracle類型,怎麼辦?
// 服務端要修改Factory的內容(在Java,C++中,改完以後還得再編譯)
// 在面向對象設計法則中,重要的開閉原則 --- 對於修改是封閉的,對於擴展是開放的.

// 需求能夠擴展子類來實現。

工廠方法

進行擴展,避免對原有數據進行修改,只須要新增代碼的子類,就能夠完成。

對於修改是封閉的,對於擴展是開放的.

<?php


// 共同接口
// 數據庫的接口
interface DB {
  function conn();
}

// 創造數據庫的接口
interface Factory {
  function createDB();
}

// 服務端開發(不知道將會被誰調用)
class DbMysql implements DB {
  public function conn() {
    echo 'conn mysql <br/>';
  }
}

class DbSqlite implements DB {
  public function conn() {
    echo 'conn sqlite  <br/>';
  }
}


class MySqlFactory implements Factory {
  public function createDB() {
    return new DbMysql();
  }
}

class SqliteFactory implements Factory {
  public function createDB() {
    return new DbSqlite();
  }
}



// ==== 服務器端添加oracle類
// 進行擴展,避免對原有數據進行修改
class orcale implements DB {
  public function conn() {
    echo 'conn orcal <br />';
  }
}

class orcaleFactory implements Factory {
  public function createDB() {
    return new orcale();
  }
}


// ------客戶端開始調用.

$fact = new MysqlFactory();
$db = $fact->createDB();
$db->conn();


$fact = new SqliteFactory();
$db = $fact->createDB();
$db->conn();

單例模式

常見使用場景:

  1. 須要數據庫類的時候

  2. 操做cookie類

  3. 上傳圖片類

DB.class.php
Upload.class.php
Cookie.class.php
// 這三個類都須要讀取配置文件信息,而配置文件是共用的,所以配置讀取類有一個對象就夠了。 
// (如何保證對象只有一個)

PHP對象何時全等

二個對象是一個的時候.

單例模式實現

  1. 封閉外部new操做

  2. 內部開公共接口,負責new操做,控制單一實例

  3. 禁止繼承覆蓋__construcotr

  4. 防止克隆

<?php

/**
  單例模式
*/

// 第一步,普通類

// class Single {

// }


// $s1 = new Single();
// $s2 = new Single();

// var_dump($s1, $s2);
// var_dump($s1 == $s2);

// ---------------------

// 第二步,封鎖new操做
// class Single {
//   // 在new 的時候會觸發魔術函數,__constructor,能夠在 __constructor 魔術函數中作操做 
//   protected function __constructor() { // 把__constructor()魔術方法保護起來, 致使的後果,一個對象都無法new。(大門關上了,須要開窗)

//   }
// }

// $s1 = new Single();


// ---------------------

// 第三步,留接口來new對象
// class Single {
//    public static function getIns() { // getIns的控制權在class內部,能夠在getIns作手腳
//      return new self(); // 返回自身實例
//    } 
//    protected function __constructor() {

//    }
// }

// $s1 = Single::getIns();
// $s2 = Single::getIns();

// var_dump($s1, $s2);
// var_dump($s1 == $s2);



// ---------------------

// 第四步,getIns要預先判斷實例
// class Single {
//    protected static $ins = null;
//    public static function getIns() { // getIns的控制權在class內部,能夠在getIns作手腳
//      if (self::$ins === null) {
//        self::$ins = new self();
//      }
//      return self::$ins;  // 返回自身實例
//    } 
//    protected function __constructor() {

//    }
// }

// $s1 = Single::getIns();
// $s2 = Single::getIns();

// var_dump($s1, $s2);
// var_dump($s1 == $s2); // true

// 問題 :繼承以後 constructor 被公開, 可使用final
// class multi extends Single {
//   public function __constructor() { // 繼承以後 constructor 被公開

//   }
// } 




// ---------------------

// 第五步,final,防止繼承時,被修改權限
// class Single {
//    protected static $ins = null;
//    public static function getIns() { // getIns的控制權在class內部,能夠在getIns作手腳
//      if (self::$ins === null) {
//        self::$ins = new self();
//      }
//      return self::$ins;  // 返回自身實例
//    } 
//    final protected function __constructor() { // 方法前加 final,則方法不能被覆蓋,類前加final,則類不能被繼承。

//    }
// }

// class multi extends Single {
//   public function __constructor() { // 繼承以後 constructor 被公開

//   }
// } 

// $s1 = Single::getIns();
// $s2 = clone $s1; // 克隆了,又產生了多個對象.

// var_dump($s1, $s2);
// var_dump($s1 === $s2); // true




// ---------------------

// 第六步,禁止clone
class Single {
   protected static $ins = null;
   public static function getIns() { // getIns的控制權在class內部,能夠在getIns作手腳
     if (self::$ins === null) {
       self::$ins = new self();
     }
     return self::$ins;  // 返回自身實例
   } 
   final protected function __constructor() { // 方法前加 final,則方法不能被覆蓋,類前加final,則類不能被繼承。

   }

   // 封鎖clone
   final protected function __clone() {

   }
}

$s1 = Single::getIns();
$s2 = clone $s1; // 克隆了,又產生了多個對象.

var_dump($s1, $s2);
var_dump($s1 === $s2); // true

觀察者模式

一個對象變化,引發其它對象的反應。可讓其它幾個對象觀察變化的對象的反應.

一對多的關係.

優勢:解耦。

觀察者模式中的三者: Subject, Observer, Client;

// Subject
attach() // 記憶多個的對象
detach()  // 告知記憶的對象,變化狀況
notify()  // 更新通知

// Observer
update() // 更新對象中執行的邏輯

// Client
// 調用添加觀察者`attach()`

JavaScript實現觀察者模式:

var select = document.querySelector('select');
var content = document.querySelector('.content');
var ad = document.querySelector('.ad');

// Subject
select.observer = {};
// 添加觀察者
select.attach = function(key, obj) {
  this.observer[key] = obj;    
}

// 刪除觀察者
select.detach = function(key) {
  delete this.observer[key];
}

// 更新通知
select.onchange = select.ontify = function() {
  for (var key in this.observer) {
    this.observer[key].update(this);
  }
}

// Observer  
// 觀察者
content.update = function(observer) { // 參數是被觀察者對象
  alert('content');
  if (observer.value) {
    // 邏輯代碼
  }
}

ad.update = function(observer) { // 參數是被觀察者對象
  alert('ad');
  if (observer.value) {
    // 邏輯代碼
  }
}


// Client
// 監聽 
select.attach('content', content); // 只須要把獨特的表示加入 對象key中
select.attach('ad', ad);

圖片描述

PHP實現觀察者模式:

單一功能原則:類或者一個方法,完成一個功能便可.

PHP中內置接口:
Splsubject
Splobserver
內置類:
Splobjectstorage

<?php

// PHP實現觀察者

// PHP5中提供了觀察者(observer)和被觀察者(subject)接口

/**
  被觀察者
 */
class User implements SplSubject {
  public $lognum;
  public $hobby;

  protected $observers = null;

  public function __construct($hobby) {
    $this->lognum = rand(1, 10);
    $this->hobby = $hobby;
    $this->observers = new SplObjectStorage();
  }

  public function login() { // 類或者一個方法,完成一個功能便可. (單一功能原則)
    // 操做session
    $this->notify();
  }

  public function attach(SplObserver $observer) {
    $this->observers->attach($observer);
  }

  public function detach(SplObserver $observer) {
    $this->observers->detach($observer);
  }

  public function notify() {
    $this->observers->rewind();
    while($this->observers->valid()) {
      $observer = $this->observers->current();
      $observer->update($this);
      $this->observers->next();      
    }
  }
}

/**
  觀察者
*/

class Secrity implements SplObserver {
  public function update(SplSubject $subject) { // 傳入的 對象是$subject,$subject是幹什麼,隨你的意.
    if($subject->lognum < 3) {
      echo '這個第' . $subject->lognum . '次安全登陸<br/>';
    } else {
      echo '這個第' . $subject->lognum . '次登陸,異常<br/>';
    }
  }    
}


class Ad implements SplObserver {
  public function update(SplSubject $subject) {
    if ($subject->hobby == 'sport') {
      echo 'sport,nba <br/>';
    } else {
      echo 'good good study, day day up<br/>';
    }
  }
}


/**
  Client
*/
$user = new User('study');
$user->attach(new Secrity());
$user->attach(new Ad());

$user->login();

職責鏈模式

也稱之爲責任鏈模式(chain of resionbility)

對象產生的過程當中,放在邏輯判斷中.
面向過程和麪向對象混雜在一塊,沒有充分拆開。

責任鏈模式:

  1. 權利越大的人管理越多,越嚴重的問題,越得往上級找,底層的人只能管理雞毛蒜皮的小事。

  2. 每一個人都有處理事情的,權利範圍.

  3. 責任鏈模式最終都須要都一級可以處理.

  4. 先處理最近的一級

每一個對象中有職責功能,上級.
每一個對象,儲存着對本身上級的引用,若是本身處理不了,交給上一級。

優勢:使用到那一級纔會new 出那一級。

<?php

header('content-type: text/html; charset=utf-8');

// 責任鏈模式

// 權利越大的人管理越多,越嚴重的問題,越得往上級找,底層的人只能管理雞毛蒜皮的小事。
// 每一個人都有處理事情的,權利範圍.

class borad {
  public $power = 1; // 處理範圍的權限
  protected $top = 'admin'; // 上級的範圍

  public function process($lev) {
    if ($lev <= $this->power) {
      echo '刪除';
    } else {
      $top = new $this->top;
      $top->process($lev);
    }
  }
}

class admin {
  public $power = 2;
  protected $top = 'police';
  public function process($lev) {
    if ($lev <= $this->power) {
      echo '封閉';
    } else {
      $top = new $this->top;
      $top->process($lev);
    }
  }
}

class police {
  protected $power;
  protected $top = null;
  public function process() {
    echo '抓!~';
  }
}

$lev = 1;

$judge = new borad(); // 距離最近的一級
$judge->process($lev);

策略模式

和工廠模式類似的一種模式

<?php

/**
  Strategy
  策略模式

  完成:加減乘除功能
*/

interface Math {
  public function calc ($op1, $op2);
}

class MathAdd implements Math {
  public function calc($op1, $op2) {
    return $op1 + $op2;
  }
}

class MathSub implements Math {
  public function calc($op1, $op2) {
    return $op1 - $op2;
  }
}

class MathMul implements Math {
  public function calc($op1, $op2) {
    return $op1 * $op2;
  }
}

class MathDiv implements Math {
  public function calc($op1, $op2) {
    if ($op2 !=0 )  return;
    return $op1 / $op2;
  }
}

// 通常思路: 根據`op`的值,製造對象,而且調用
$op = 'Add';

// 封裝一個虛擬計算器,中能夠 調用到實際計算器
class CMath {
  protected $calc = null;

  public function __construct($type) {
    $calc = 'Math' . $type;
    $this->calc = new $calc();
  }

  public function calc($op1, $op2) {
    return $this->calc->calc($op1, $op2);
  }
}


$cmath = new CMath($op);
var_dump($cmath->calc(10, 100));

工廠方法和策略模式的區別:
工廠方法是傳遞不一樣參數,直接把零件(子類)進行操做。
策略模式是,真實的子類,虛擬成一個父類, 父類中操做(零件)子類。不須要直接碰子類,聚合成一個父類。

裝飾器模式

問題:繼承層次愈來愈多、

<?php

// 場景:發佈一篇文章

class Article {
  protected $content;

  public function __construct($content) {
    $this->content = $content;
  }

  public function decorator() {
    return $this->content;
  }
}

$art = new Article('goods goods study, day day up <br/>');
echo $art->decorator();

// -----------------------------------------------------
// 文章須要, 須要編輯人員專門編輯
class BianArt extends article {
  // 從新加工對decorator
  public function summary() {
    return $this->content . '編輯摘要 <br/>';
  }
}

$art = new BianArt('goods goods study, day day');
echo $art->summary();

// -----------------------------------------------------
// 文章須要, 須要作SEO
class SeoArt extends BianArt {
  public function seo() {
    $content = $this->summary();
    return $content . 'seo <br />';
  }
}

$art = new SeoArt('lz');
echo $art->seo();

// -----------------------------------------------------
// 文章須要,廣告部單獨管理
class Ad extends SeoArt {
  // 層次愈來愈深,目的是:給文章添加各類內容

}

// 繼承層次愈來愈多,裝飾器模式能夠解決,變成倆級繼承

使用裝飾器模式,修改多級繼承

父類負責主要邏輯,子類負責裝飾,修飾。(重寫父類的方法,裝飾以後再次返回)

<?php

// 裝飾器模式

class BaseArt {
  protected $content; // 文章內容
  protected $art = null; // 文章對象

  public function __construct($content) {
    $this->content = $content;
  }

  public function decorator() {
    return $this->content;
  }
}  

// 編輯文章
class BianArt extends BaseArt {
  
  public function __construct(BaseArt $art) {
    $this->art = $art;
    $this->decorator();
  } 

  public function decorator() {
    return $this->content = $this->art->decorator() . '編輯人員,文章摘要';
  }
}

// SEO人員
class SeoArt extends BaseArt {
  public function __construct(BaseArt $art) {
    $this->art = $art;
    $this->decorator();
  } 

  public function decorator() {
    return $this->content = $this->art->decorator() . 'SEO';
  }
}


$art = new BaseArt('day day up');
// echo $art->decorator();

$art1 = new BianArt($art);
// echo $art1->decorator();

$art2 = new SeoArt($art1);
echo $art2->decorator();

適配器模式

把不適用的格式或者數據類型,轉換成適用目前場景

<?php

// 適配器模式

// 服務器端代碼
class tianqi {
  public static function show() {
    $today = array('tep' => 28, 'wind' => 7, 'sun' => 1);
    return serialize($today);
  }
}   


// 增長一個代理,適配器
class AdapterTainqi extends tianqi {
  public static function show() {
    $today = parent::show();
    $today = unserialize($today);
    $today = json_encode($today);
    return $today;
  }
}



// =====客戶端調用=====
$taiqni = unserialize(tianqi::show());
echo '溫度:',$taiqni['tep'], '風力:', $taiqni['wind'] , '<br/>';



// java客戶端,並不認識PHP的串行化後的字符串。使用適配器模式,轉成想通模式。

$tq = AdapterTainqi::show();
$td = json_decode($tq);
echo '溫度:',$td->tep, '風力:', $td->wind;

橋接模式

在某種場景下,多個條件有共同做用,增長耦合關係,減小邏輯複雜程度
這個世界上的因素都不是單一的,都是相互耦合的.

<?php

// 橋接模式 bridge
// 功能:論壇站內給用戶發送消息,能夠是站內短信,emial,手機信息

abstract class info {
  protected $send = null;

  public function __construct($send) {
    $this->send = $send;
  }

  abstract public function msg($content);

  public function send($to, $content) {
    $content = $this->msg($content);
    $this->send->send($to, $content);
  }
}

class zn {
  public function send($to, $content) {
    echo 'zn: ', $to, '內容是:', $content;
  }
}

class email {
  public function send($to, $content) {
    echo 'email: ', $to, '內容是:', $content;
  }
}

class sms {
  public function send($to, $content) {
    echo 'sms: ', $to, '內容是:', $content;
  }
}


class commonInfo extends info {
  public function msg($content) {
    return 'common'. $content;
  }
}

class warnInfo extends info {
  public function msg($content) {
    return 'warn'. $content;
  }
}

class dangerInfo extends info {
  public function msg($content) {
    return 'danger'. $content;
  }
}


// 站內發普通訊息
$commonInfo = new commonInfo(new zn());
$commonInfo->send('小明', '吃晚飯');


// sms發普通訊息
$commonInfo = new commonInfo(new sms());
$commonInfo->send('小紅', '吃晚飯');
相關文章
相關標籤/搜索