設計模式簡介
網上有很多設計模式的介紹,也借鑒了很多。因此以下只是說自己對它的理解,若有錯誤之處,歡迎指出。設計模式是經過眾多編程實踐后,對面向對象編程總結的一些經驗,不同的設計模式有不同的優勢。但總的來說是為了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性幾個方面。由此可見,在項目中采用設計模式思維去設計代碼很重要,合適的設計模式讓你的項目更加規范,嚴謹。
設計模式的類型
創建型模式
工廠模式(Factory Pattern)
抽象工廠模式(Abstract Factory Pattern)
單例模式(Singleton Pattern)
建造者模式(Builder Pattern)
原型模式(Prototype Pattern)
這些設計模式提供了一種在創建對象的同時隱藏創建邏輯的方式,而不是使用新的運算符直接實例化對象。這使得程序在判斷針對某個給定實例需要創建哪些對象時更加靈活。
結構型模式
適配器模式(Adapter Pattern)
橋接模式(Bridge Pattern)
過濾器模式(Filter、Criteria Pattern)
組合模式(Composite Pattern)
裝飾器模式(Decorator Pattern)
外觀模式(Facade Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)
這些設計模式關注類和對象的組合。繼承的概念被用來組合接口和定義組合對象獲得新功能的方式
行為型模式
責任鏈模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解釋器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
備忘錄模式(Memento Pattern)
觀察者模式(Observer Pattern)
狀態模式(State Pattern)
空對象模式(Null Object Pattern)
策略模式(Strategy Pattern)
模板模式(Template Pattern)
訪問者模式(Visitor Pattern)
這些設計模式特別關注對象之間的通信。
常用設計模式總結
工廠模式
工廠模式是用工廠方法生成對象,而不是直接new一個對象。
假設我們在demo命名空間下有一個名叫Db的數據庫操作類,用普通的方法,如果我們想去創建一個Db的對象,我們會直接new一個出來。
$db = new demo\Db();
工廠模式就是用一個工廠方法替換掉直接new一個對象的操作,以后想創建對象就調用這個工廠方法。
<?php
namespace demo;
class Factory{
static public function createDb(){
$db = new Db();
return $db;
}
}
$db= demo\Factory::createDb();
工廠模式有什么好處呢, 我們的項目中多處都對Db類進行了new的操作,如果這個類發生了一些更改,比如說類名或者是參數的改變,沒用工廠模式的話我們就需要進行多處更改,而工廠模式只需要改這個工廠類就行了。很多其他設計模式也是依賴于工廠模式的。
單例模式
單例模式使某個類的對象僅能創建一次,通常一個項目中會多次用的Db這個數據庫連接類,如果在每個地方都調用工廠方法創建一個數據庫連接類,這樣是比較消耗資源的,我們只需要一個數據庫連接,單例模式就是來解決這個問題的。
我們打開Db類,首先把構造方法設置為私有的,這樣就禁止了在其他地方直接new我們的Db類
<?php
namespace demo;
class Db{
protected $db;
private function __construct(){
}
static public function getInstance(){
//條件判斷Db類是否已經new過
if (self::$db) {
return self::$db;
} else {
//構造方法被設置為了私有的,外部不能直接new,但自己內部可以new
self::$db = new self();
return self::$db;
}
}
//下面省略一系列操作數據庫的方法
}
Db類的構造方法設置為了私有的,那我們在工廠類中也不能直接new了,現在來修改我們的工廠類
<?php
namespace demo;
class Factory{
static public function createDb(){
$db = Db::getInstance;
return $db;
}
}
現在不管我們調用多少次工廠方法,我們的數據庫連接都只會被創建一次。
注冊樹模式
注冊樹模式可以把我們的對象放在全局的樹上,讓對象可以全局共享
下面我們來編寫一個注冊樹的類,包含set,get,_unset三個操作。
<?php
namespace demo;
class Register{
protected static $objects;
static public function set($alias,$object){
self::$objedts[$alias] = $object;
}
static public function get($name){
return self::$objedts[$name];
}
//unset是php中的關鍵詞,所以起名為_unset,移除對象
static public function _unset($alias){
unset(self::$objedts[$alias]);
}
}
下面我們再把工廠方法改一下
<?php
namespace demo;
class Factory{
static public function createDb(){
$db = Db::getInstance;
//把單例模式生成的對象放在注冊樹上
Register::set('db',$db);
}
}
現在這個工廠方法只需要調用一次,以后再需要使用數據庫連接對象,直接從全局的注冊樹上拿就行了
$db = Register::get("db");
至于這個工廠方法是么時候調用,可以在程序初始化的時候,我們的業務邏輯代碼只需要在注冊樹上把這個對象讀取出來即可。
適配器模式
適配器模式可以將截然不同的函數接口封裝成統一的API。例如,PHP的數據庫操作有mysql,mysqli,pdo 三種,可以用適配器模式統一成一致。類似的場景還有cache適配器,將memcache,redis,file,apc等不同的緩存函數,統一成一致。
下面還是以數據庫操作為例。
首先定義數據庫接口。
interface IDatabase
{
function connect($host, $user, $passwd, $dbname);
function query($sql);
function close();
}
接下來編寫不同的數據庫類,使它們變成一樣的接口。
這里主要講mysqli和pdo兩個
<?php
namespace demo\Database;
use demo\IDatabase;
class MySQLi implements IDatabase
{
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 demo\Database;
use demo\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);
}
}
外部調用
//通過改變實例化對象即可實現切換
//$db = new demo\Database\PDO();
$db = new demo\Database\MySQLi();
$db->connect('127.0.0.1','root','root','test');
$db->query("show databases");
$db->close();
策略模式
首先聲明一個策略的接口文件,它約定了策略有哪些行為。
<?php
interface UserStrategy {
//約定了兩個方法
function showAd();//顯示廣告
function showCategory();//顯示一個類目
}
再來定義具體的策略文件
女性用戶
class FemaleUserStrategy implements UserStrategy {
function showAd()
{
echo "熱門女裝";
}
function showCategory()
{
echo "女裝";
}
}
男性用戶
class MaleUserStrategy implements UserStrategy {
function showAd()
{
echo "熱門手機";
}
function showCategory()
{
echo "電子產品";
}
}
頁面
class Page
{
protected $strategy;
function index()
{
echo "AD:";
$this->strategy->showAd();
echo "Category";
$this->strategy->showCategory();
}
function setStrategy(\demo\UserStrategy $strategy)
{
$this->strategy = $strategy;
}
}
$page = new Page;
if (isset($_GET['female'])){
$strategy = new \demo\FemaleUserStrategy();
} else {
$strategy = new \demo\MaleUserStrategy();
}
$page->setStrategy($strategy);
$page->index();
——未完——