面向对象 - 设计模式 - 单例模式

问题

  • 经过良好设计的系统一般通过方法调用来传递对象实例。每个类都会与背景环境保持独立,并通过清晰的通讯方式来与系统中其他部分进行协作。有时你需要使用一些作为对象间沟通渠道的类,此时就不得不引入依赖关系。
  • 假设有一个用于保存应用程序信息的 Preferences 类。我们可能会使用一个 Perferences 对象来保存诸如DSN(用于保存数据库的表及用户信息)字符串,URL根目录、文件路径等数据。这些信息在你每次部署程序时都可能会有所不同。改对象也可被用作一个“公告板”,它是可以被系统中其他无关对象设置和获取消息的中心。
  • 但在对象中传递 Preferences 对象并不总是个好主意。你可以让原来并不使用 Preferences 对象的类强制性地接受 Preferences 对象,以便这些类能传递 Preferences 对象给其它对象,但这样做产生了另一种形式的耦合。
  • 我们需要保证系统中的所有对象都使用同一个 Preferences 对象。我们不希望一些对象在一个 Preferences 对象上设值,而其它对象从另外一个完全不同的 Preferences 对象上读取数据。
  • 让我们提炼出这个问题的几个关键点:
    1. Preferences 对象应该可以被系统中的任何对象使用
    2. Preferences 对象不应该被存储在会被覆写的全局变量中。
    3. 系统中不应超过一个 Preferences 对象。也就是说,Y对象可以设置 Preferences 对象的一个属性,而Z对象不需要通过其它对象(假设Y和Z都可以访问 Preferences 对象)就可以直接获取该属性的值。

实现

  • 使用静态方法和静态属性来间接实例化对象。
class Preferences {

    private $props = array();

    private static $instance = null;

    /**
     * 构造函数
     */
    private function __construct()
    {
    }

    /**
    * 不允许深度复制
    */
    private function __clone()
    {
    }

    /**
    * 不允许serialize
    */
    private function __sleep()
    {
    }

    /**
    * 不允许unserialize
    */
    private  function __wakeup()
    {
    } 

    /**
     * 获取单例
     * @return 实例化后的对象
     */
    public static function getInstance()
    {
        if (empty(self::$instance)) {
            self::$instance = new Preferences();
        }
        return self::$instance;
    }

    /**
     * 设置属性值
     * @param string $key 键
     * @param string $val 值
     * @return boolen 布尔值
     */
    public function setProperty($key, $val)
    {
        $this->props[$key] = $val;
        return true;
    }

    /**
     * 获取属性值
     * @param string $key 键
     * @return $this->props 属性值
     */
    public function getProperty($key = null)
    {
        if (is_null($key)) {
            return $this->props;
        } else {
            return $this->props[$key];
        }
    }
}
  • $instance 属性设置为 privatestatic ,因此不能再类外部被访问。而 getInstance() 方法是 public 且 static 的,所有在脚本的任何地方都可被调用。
$pref = Preferences::getInstance();
$pref->setProperty('subject', 'php');

unset($pref); // 移除引用

$pref2 = Preferences::getInstance();
$resp = $pref2->getProperty('subject');
var_dump($resp); //该属性值并没有丢失

response:php

  • 静态方法不能访问普通的对象属性,因为根据静态的定义,它只能被类而不是对象调用。但静态方法可以访问静态属性。所以当 getInstance() 被调用时,我们会检查 Preference::$instance 属性。如果为空,那么创建一个 Preferences 对象实例并把它保存在 $instance 属性中,然后我们把实例返回给调用代码。因为静态方法 getInstance() 是 Preferences 类的一部分,所以尽管构造方法是私有的,但是实例化 Preferences 对象完全没有问题。

  • 单例模式UML类图
    单例模式UML类图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值