单例模式
- 生成对象的问题和解决方案
abstract class Employee
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
abstract function fire();
}
class Minion extends Employee
{
function fire()
{
print "{$this->name}:I'll clear my desk\n";
}
}
class NastyBoss
{
private $employees = array();
function addEmployee($employeeName)
{
$this->employees[] = new Minion($employeeName);
}
function projectFail()
{
if (count($this->employees) > 0) {
$emp = array_pop($this->employees);
$emp->fire();
}
}
}
$boss = new NastyBoss();
$boss->addEmployee("harry");
$boss->addEmployee("bob");
$boss->addEmployee("mary");
$boss->projectFail();
由于在NastyBoss类中直接实例化Minion对象,代码的灵活性受到限制。如果NastyBoss对象可以使用Employee类的任何实例,那么代码在运行时就能应对更多特殊的Employee。如下类图:
如果NastyBoss类不实例化Minion对象,那么Minion对象从何而来?在方法声明中限制参数类型来巧妙避开这个问题,然后除了在测试时实例化对象,在其他时候尽量避免提及。
如果是这里存在一个原则的话,那便是“把对象实例化的工作委托出来”。我们可以委托一个独立的类或方法来生成Employee对象。
abstract class Employee
{
protected $name;
private static $types = array("minion", 'clueup', 'wellconnected');
static function recruit($name)
{
$num = rand(1, count(self::$types)) - 1;
$class = self::$types[$num];
return new $class($name);
}
public function __construct($name)
{
$this->name = $name;
}
abstract function fire();
}
class wellConnected extends Employee
{
function fire()
{
print "{$this->name}: i'll call my dad\n";
}
}
$boss = new NastyBoss();
$boss->addEmployee(Employee::recruit("harry"));
$boss->addEmployee(Employee::recruit("bob"));
$boss->addEmployee(Employee::recruit("mary"));
- 单例模式
经过良好设计的系统一般通过方法调用来传递对象实例。每个类都会与背景环境保持独立,并通过清晰的通信方式来与系统中其他部分进行协作。有时你需要使用一些作为对象间沟通渠道的类,此时就不得不引入依赖关系。
下面创建一个无法从自身外部来创建实例的类:
class Preferences
{
private $props = array();
private static $instance;
private function __construct()
{
}
public static function getInstance()
{
if (empty(self::$instance)) {
self::$instance = new Preferences();
}
return self::$instance;
}
public function setProperty($key, $val)
{
$this->props[$key] = $val;
}
public function getProperty($key)
{
return $this->props[$key];
}
}
$pref = Preferences::getInstance();
$pref->setProperty("name", "matt");
unset($pref);
$pref2 = Preferences::getInstance();
print $pref2->getProperty("name") . "\n";
使用单例模式和使用全局变量都可能被误用,适度地使用单例模式可以改进系统设计。在系统中传递那些不必要的对象令人厌烦,而单例模式可以让你从中解脱。