單例模式和工廠模式


職責和單例模式

  單例模式被認為是職責模式,這是因為它將創建對象的控制權委托到一個單一的訪問點上.在任何時候,應用程序中都只有這個類僅有的一個實例存在.

所有的單例類至少擁有以下三種公共元素:

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

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

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

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

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

  返回實例引用的這個方法通常被命名為getInstance().這個方法必須是靜態的,而且如果它還沒有實例化,就必須進行實例化.getInstance()方法通過使用instanceof操作符和self關鍵字,可以檢測到類是否已經被初始化.如果保存實例靜態成員為空或者還不是類自身的一個實例,那么這個實例將會被創建並保存到存放實例的變量中.

使用單例類:

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

工廠模式

  工廠類是指包含了一個專門用來創建其他對象的方法的類.工廠類在多態性編程實踐中是至關重要的.它允許動態地替換類,修改配置,並且通常會使應用程序更加靈活.

  通常,工廠模式有一個關鍵的構造,即根據一般原則被命名為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的規范來編寫,而實現類將負責執行用來操作特定數據庫的查詢.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM