单例模式和工厂模式


职责和单例模式

  单例模式被认为是职责模式,这是因为它将创建对象的控制权委托到一个单一的访问点上.在任何时候,应用程序中都只有这个类仅有的一个实例存在.

所有的单例类至少拥有以下三种公共元素:

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