PHP常用設計模式詳解 單例模式: php交流群:159789818 特性:單例類只能有一個實例 類內__construct構造函數私有化,防止new實例 類內__clone私有化,防止複製對象 設置一個$instance私有靜態屬性,為了保存當前類的實例 設置一個getInstance公有方法,為 ...
PHP常用設計模式詳解
單例模式:
php交流群:159789818
特性:單例類只能有一個實例
- 類內__construct構造函數私有化,防止new實例
- 類內__clone私有化,防止複製對象
- 設置一個$instance私有靜態屬性,為了保存當前類的實例
- 設置一個getInstance公有方法,為了獲取當前類的實例
- 減少new對象操作,合理使用記憶體
通常使用在獲取某個全局配置項,或者資料庫連接、操作等類上
Demo:
1 <?php 2 Class Demo{ 3 //用於保存當前類的實例 4 private static $instance; 5 //構造函數私有化,防止直接new當前對象 6 private function __construct(){} 7 //析構函數私有化,防止從外部直接複製當前對象 8 private function __clone(){} 9 //getInstance公有函數用於獲取當前類的實例 10 public static function getInstance() 11 { 12 //判斷當前類成員變數instance是否為空 13 //如果不為空,則直接返回類的實例 14 //如果為空,則new一個當前類的實例,並保存到類成員變數 15 //instance中,然後直接返回成員變數 16 if(empty(self::$instance)) 17 { 18 //將實例保存到instance成員變數中 19 self::$instance = new static(); 20 //直接返回成員變數 21 return self::$instance; 22 }else{ 23 //直接返回類實例 24 return self::$instance; 25 } 26 } 27 } 28 $demo1 = Demo::getInstance();//獲取到實例 29 $demo2 = new Demo();//報錯
工廠模式(Factory Design Pattern)
特性:
- 降低系統耦合度
- 遵循開發-封閉原則 對修改封閉, 對擴展開放
- 通過工廠創建類的實例,而不是直接操作new關鍵字創建類的實例
- 已經使用的類內部發生改變,哪不需要在所有的地方都改變,只需要在類工廠類里改變既可
- 例如,支付寶微信銀行等對接就可以寫個工廠模式來對接
抽象工廠Demo:
<?php //PaymentFactory.php interface PaymentFactory { //請求收款碼 public function QRcode(); //監聽收款 public function Listen(); } interface createPay { //將對象的創建抽象成一個介面 function createOpen($class,$data);//內向創建 function createIntro($class,$data);//外向創建 } //微信支付類 Class WxPay implements PayMentFactory { public function QRcode() { //微信業務邏輯代碼 //返回收款碼以及訂單相關參數 return "我是微信二維碼"; } public function Listen() { //微信業務邏輯代碼 //返回訂單結果 return "正在監聽"; } } //阿裡支付類 Class aliyun implements PayMentFactory { public function QRcode() { //業務邏輯代碼 //返回收款碼以及訂單相關參數 return "我是支付寶二維碼"; } public function Listen() { //業務邏輯代碼 //返回訂單結果 return "正在監聽"; } } //實現createPay介面 class CreateP implements createPay { public function createOpen($class,$data =[]) { return new $class($data); } public function createIntro($class,$data = []) { return new $class($data); } } //開發者類 class Client{ static function Get($class,$data = []) { $fac = new CreateP(); // var_dump($fac); return $fac->createOpen($class,$data); } } $pay = Client::Get("WxPay"); echo $pay->QRcode(); //輸出,我是微信二維碼
註冊模式 Register
特性:
- 解決全局共用和交換對象
- 創建好的對象,掛到某個全局數組上
- 需要的時候直接去該數組上獲取即可
- 將對象實例註冊到全局樹上
Demo:
<?php //全局註冊類 Class Register { //存儲類的實例 public static $maps; //註冊操作 public static function Set($name,$cla) { //判斷是否已經存儲 if(array_key_exists($name,self::$maps)) { //如果全局maps內已有則直接返回 return true; }else{ //如果沒有name 則將實例和name按鍵值對存儲到成員變數內 self::$maps[$name] = $cla; return true; } } //獲取類實例 public static function Get($name) { //判斷name值是否存在 if(array_key_exists($name,self::$maps)) { //如果存在則直接返回對應的類的實例 return self::$maps[$name]; }else{ //如果不存在,則返回false或者其他 return false; } } }
適配器模式 Adapter :
特性:
- 將各種不同的函數介面封裝到統一的api
- 降低因為介面底層代碼的不同,而導致的調用?(個人理解)
Demo(網上直接copy來的):
介面 IDatabase <?php namespace IMooc; interface IDatabase { function connect($host, $user, $passwd, $dbname); function query($sql); function close(); } MySQL <?php namespace IMooc\Database; use IMooc\IDatabase; class MySQL implements IDatabase { protected $conn; function connect($host, $user, $passwd, $dbname) { $conn = mysql_connect($host, $user, $passwd); mysql_select_db($dbname, $conn); $this->conn = $conn; } function query($sql) { $res = mysql_query($sql, $this->conn); return $res; } function close() { mysql_close($this->conn); } } MySQLi <?php namespace IMooc\Database; use IMooc\IDatabase; class MySQLi implements IDatabase { protected $conn; function connect($host, $user, $passwd, $dbname) { $conn = mysqli_connect($host, $user, $passwd, $dbname); $this->conn = $conn; } function query($sql) { return mysqli_query($this->conn, $sql); } function close() { mysqli_close($this->conn); } } PDO <?php namespace IMooc\Database; use IMooc\IDatabase; class PDO implements IDatabase { protected $conn; function connect($host, $user, $passwd, $dbname) { $conn = new \PDO("mysql:host=$host;dbname=$dbname", $user, $passwd); $this->conn = $conn; } function query($sql) { return $this->conn->query($sql); } function close() { unset($this->conn); } }
通過以上案例,PHP與MySQL的資料庫交互有三套API,在不同的場景下可能使用不同的API,那麼開發好的代碼,換一個環境,可能就要改變它的資料庫API,那麼就要改寫所有的代碼,使用適配器模式之後,就可以使用統一的API去屏蔽底層的API差異帶來的環境改變之後需要改寫代碼的問題
觀察者模式
特性:
- 觀察者模式(Observer),當一個對象狀態發生變化時,依賴它的對象全部會收到通知,並自動更新
- 一個事件發生後,要執行一連串更新操作。傳統的編程思想,就是在這個事件的代碼後直接加入處理的邏輯。當更新的邏輯增多之後,代碼會變得難以維護。這種方式是耦合的,侵入式的,增加新的邏輯需要修改事件的主體代碼。
- 觀察者模式實現了低耦合,非侵入式的通知與更新機制
Demo:
<?php //EventGenerator //事件觸發抽象類 abstract class EvemtGenerator { //存儲觀察者類 private $observer =[]; //添加觀察者操作 public function AddOb(Observer $observer) { $this->observer[] = $observer; } //觀察者通知操作 public function notify() { //迴圈類成員變數,並執行對應的觀察者更新方法 foreach ($this->observer as $observer) { //執行每個觀察者類內的更新操作 $observer->update(); } } } //定義觀察者介面 interface Observer { public function update(); } //實現一個被觀察者類 Class Test extends EvemtGenerator { //實現一個登陸方法 public function login() { return "登陸成功"; } } //實現一個觀察者 Class Observer1 implements Observer { //定義一個邏輯更新操作 例如:添加了csrf驗證 public function update() { if($_POST['csrf'] == getCsrf()) { return true; }else{ exit("csrf驗證不正確"); } } } //實例化Test類 被觀察 $event = new Test(); $event->AddOb(new Observer1()); $event->login(); //更新通知操作 $event->notify();
策略模式:
特性:
- 將一組特定的行為和演算法封裝成類,以適應某些特定的上下文環境
- 方便系統維護,例如:為每一個用戶登陸時展現不同的頁面
- 解耦
Demo:
//定義策略介面,規範策略行為 interface UserStrategy { public function show(); public function message(); } //定義一個喜歡買西裝的用戶類 Class SuitUser implements UserStrategy { public function show() { //為用戶跳轉到西裝頁面 return "跳轉到西裝頁面"; } public function message() { //發送message echo "即將為您展示最新的西裝某某某"; } } //定義一個喜歡買裙子的用戶類 Class skirtUser implements UserStrategy { public function show() { //為用戶跳轉到西裝頁面 return "跳轉到裙子推薦頁面"; } public function message() { //發送message echo "即將為您展示最新的裙子某某某"; } } //定義一個業務類 Class Users { //存儲對應的用戶類 private $userCla; //執行策略介面 public function Start() { echo "跳轉頁面是:".$this->strategy->show(); echo "消息是:".$this->strategy->message(); } //註冊對應的用戶類 public function SetStrategy(UserStrategy $strategy) { $this->$userCla = $strategy; } } //業務邏輯代碼 判斷用戶習性 $user1 = "西裝"; $user2 = "裙子"; $userL = new Users(); //如果用戶習性為喜歡看西裝或者買西裝則 if ($user1 == "西裝"){ $userL->SetStrategy(new SuitUser()); $userL->Start(); }