單例模式和工廠模式

職責和單例模式

  單例模式被認爲是職責模式,這是由於它將建立對象的控制權委託到一個單一的訪問點上.在任什麼時候候,應用程序中都只有這個類僅有的一個實例存在.php

全部的單例類至少擁有如下三種公共元素:mysql

1.它們必須擁有一個構造函數,而且必須被標記爲private.sql

2.它們擁有一個保存類的實例的靜態成員變量.數據庫

3.它們擁有一個訪問這個實例的公共的靜態方法.編程

  和普通類不一樣的是,單例類不能在其餘類中直接實例化.單例類只能被其自身實例化.要得到這種限制效果,__contruct()方法必須被標記爲private.若是試圖用private構造函數構造一個類,就會獲得一個可訪問性級別的錯誤.ide

  要讓單例類起做用,就必須使其爲其餘類提供一個實例,用他調用各類方法.單例類不會建立實例副本,而是會向單例類內部存儲的實例返回一個引用.結果是單例類不會重複佔用內存和系統資源,從而讓應用程序的其餘部分更好地使用這些資源.做爲這-模式的一部分,必須建立一個空的私有的__clone()方法,以防止對象被複制或者克隆.函數

  返回實例引用的這個方法一般被命名爲getInstance().這個方法必須是靜態的,並且若是它尚未實例化,就必須進行實例化.getInstance()方法經過使用instanceof操做符和self關鍵字,能夠檢測到類是否已經被初始化.若是保存實例靜態成員爲空或者還不是類自身的一個實例,那麼這個實例將會被建立並保存到存放實例的變量中.this

使用單例類:spa

class Database{

    private $_db;
    static $_instance;
    private function __construct(){
        $this->_db = pg_connect('dbname=example_db');
    }

    private __clone(){};

    public static function getInstance(){
        if(!(self::$_instance instanceof self)){
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function query($sql){
        //使用$this->_db執行一個查詢
        return pg_query($this->_db,$sql);
    }
}

$db = Database::getInstance();
$db->query('SELECT * FROM example_table');
View Code

工廠模式

  工廠類是指包含了一個專門用來建立其餘對象的方法的類.工廠類在多態性編程實踐中是相當重要的.它容許動態地替換類,修改配置,而且一般會使應用程序更加靈活.code

  一般,工廠模式有一個關鍵的構造,即根據通常原則被命名爲factory的靜態方法.然而,這只是一種原則,工廠方法能夠任意命名.這個靜態方法還能夠接受任意數量的參數,而且必須返回一個對象.

基本的工廠類:

class MyObject{
    //對象將從工廠類返回
}
class MyFactory{
    public static function factory(){
        //返回對象的一個新實例
        return new MyObject();
    }
}

$instance = MyFactory::factory();
View Code

使用工廠類解析圖像文件

<?php

interface IImage{
    function getHeight();
    function getWidth();
    function getData();
}

class Image_PNG implements IImage{
    private $_width,$_height,$_data;
    public function __construct($file){
        $this->_file = $file;
        $this->_parse();
    }
    private function _parse(){
        //完成PNG格式的解析工做
        //並填充$_width,$_height和$_data
    }
    public function getWidth(){
        return $this->_width;
    }
    public function getHeight(){
        return $this->_height;
    }
    public function getData(){
        return $this->_data;
    }
}

class Image_JPEG implements IImage{
    private $_width,$_height,$_data;
    public function __construct($file){
        $this->_file = $file;
        $this->_parse();
    }
    private function _parse(){
        //完成JPEG格式的解析工做
        //並填充$_width,$_height和$_data
    }
    public function getWidth(){
        return $this->_width;
    }
    public function getHeight(){
        return $this->_height;
    }
    public function getData(){
        return $this->_data;
    }
}

class ImageFactory{
    public static function factory($file){
        $pathParts = pathinfo($file);
        switch (strtolower($pathParts['extension'])) {
            case 'jpg':
                $ret = new Image_JPEG($file);
                break;
            case 'png':
                $ret = new Image_PNG($file);
            default:
                //有問題
        }
        if($ret instanceof IImage){
            return $ret;
        }else{
            //有問題
        }
    }
}

$image = ImageFactory::factory('/path/to/my.jpg');
//$image如今是Image_JPEG類的一個實例
echo $image->getWidth();
View Code

  上例中,ImageFactory是工廠類,由於它返回了一個類的實例.類的類型是經過調用pathinfo()函數得到的文件拓展名類決定的.因爲它是一個工廠類,產生的應用程序不須要知道這些圖像解析的細節,須要知道的是工廠返回的對象支持IImage接口.

  使用這一技術使得API更加容易調用,這是由於它只有一個類和一個方法.若是不使用工廠模式,API的調用者將須要決定應該調用的類,而後去調用某個特定的類,這樣就須要對工廠的行爲進行復制.

工廠類解決數據庫可移植性問題

interface IDatabaseBindings{
    public function userExists($email);
}
class PGSQL implements IDatabaseBindings{
    protected $_connection;
    public function __construct(){
        $this->_connection = pg_connect('dbname=example_db');
    }

    public function userExists($email){
        $emailEscaped = pg_escape_string($email);
        $query = "select 1 from users where email ='".$emailEscaped."'";
        if($result = pg_query($query,$this->_connection)){
            return (pg_num_rows($result) > 0)?true:false;
        }else{
            return false;
        }
    }

}

class MYSQL implements IDatabaseBindings{
    protected $_connection;
    public function __construct(){
        $this->_connection = mysql_connect('localhost');
        mysql_select_db('example_db',$this->_connection);
    }

    public function userExists($email){
        $emailEscaped = mysql_real_escape_string($email);
        $query = "select 1 from users where email ='".$emailEscaped."'";
        if($result = mysql_query($query,$this->_connection)){
            return (mysql_num_rows($result) > 0)?true:false;
        }else{
            return false;
        }
    }
}

class DatabaseFactory{
    public static function factory(){
        $type = loadtypefromconfigfile();
        switch ($type) {
        case 'PGSQL':
            return new PGSQL();
            break;
        case 'MYSQL':
            return new MYSQL();
            break;
        }
    }
}
//---用法---
$db = DatabaseFactory::factory();
$db->userExists('person@example.com');
View Code

  以上代碼建立一個DatabaseFactory類,它將會實例化並返回與IDatabaseBindings接口兼容的對象.應用程序將會根據IDatabaseBindings的規範來編寫,而實現類將負責執行用來操做特定數據庫的查詢.

相關文章
相關標籤/搜索