1、单例模式
单例模式,顾名思义,就是只有一个实例。作为对象的创建模式,单例模式确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
单例模式有三个要点:
- 一个类只能有一个实例
- 该类必须自行创建这个实例
- 该类必须向整个系统提供这个实例
为什么要使用单例模式:
- PHP应用主要在于数据库应用,一个应用中会有大量的数据库操作,在使用面向对象的开发时,如果使用单例模式,可以避免大量的new操作消耗的资源,还可以减少数据库连接,这样就不会出现too many connections的情况
- 如果系统中需要一个类来全局控制某些配置信息,那么单例模式可以很方便的实现,这个可以看看zend framework的FrontController部分
- 在一次页面请求中,便于进行调试,因为所有的代码(如数据库操作类demo)都集中在一个类中,可以在类中设置钩子,输出日志,从而避免导出var_dump、echo
例子:
<?php /** * 设计模式 - 单例模式 * * $_instance必须声明为静态的私有变量 * 构造函数必须声明为私有,防止外部程序new类从而失去单例模式的意义 * getInstance()方法biubiu设置为共有的,必须调用此方法返回实例的一个引用 * ::操作符只能访问静态变量和静态函数 * new对象都会消耗内存 * 使用场景:最常用的地方是数据库连接 * 使用单例模式生成一个对象后,该对象可以被其他众多对象所使用 * */ class Simple { //保存实例在此属性中 private static $_instance; //构造函数声明为private,防止直接创建对象 private function __construct() { } //单例方法 public static function get_instance() { if(!isset(self::$_instance)) { self::$_instance=new self(); } return self::$_instance(); } //阻止用户复制对象实例 private function __clone() { trigger_error('Clone is not allow', E_USER_ERROR); } }
2、简单工厂模式
- 抽象基类:类中定义抽象的一些方法,用以在子类中实现
- 继承自抽象的子类:实现基类中的抽象方法
- 工厂类:用以实例化所有对应的子类
通过采用面向对象的继承特性,可以很容易的对原有程序进行扩展,如“乘方”,“开方”,“对数”,”三角函数“等,以及还可以避免加载没有必要的代码/** * * 定义抽象的类,让子类去继承并实现 * */ abstract class Operation { //抽象方法不能包含函数体 abstract public function getValue($n1, $n2); } /** * 加法类 */ class OperationAdd extends Operation { public function getValue($n1, $n2) { return $n1+$n2; } } /** * 减法类 */ class OperationSub extends Operation { public function getValue($n1, $n2) { return $n1-$n2; } } /** * 乘法类 */ class OperationSub extends Operation { public function getValue($n1, $n2) { return $n1*$n2; } } /** * 除法类 */ class OperationSub extends Operation { public function getValue($n1, $n2) { try { if($n2 == 0) { throw new Exception('除数不能为0'); } else { return $n1/$n2 } } catch(Exception $e) { echo '错误消息:'.$e->getMessage(); } } }
如果现在需要增加一个求余的类,会非常简单。只需要灵哇写一个类(该类继承虚拟基类),在类中完成相应的功能,而且大大的降低了耦合度,方便日后的维护和扩展。
现在还有一个问题没有解决:如何让程序根据用户输入的操作符实例化相应的对象呢?/** * 求余类 */ class OperationSub extends Operation { public function getValue($n1, $n2) { return $n1%$n2; } }
解决办法:使用一个单独的类来实现实例化过程,这个类就是工厂
其他关于此模式的笔记:/** * * 工程类,主要用来创建对象 * 功能:根据输入的运算符号,工厂就能实例化出合适的对象 */ class Factory { public static function createObj($operate) { switch($operate) { case '+': return new OperationAdd(); break; case '-': return new OperationSub(); break; case '*': return new OperationSub(); break; case '/': return new OperationDiv(); break; } } } $test = Factory::createObj('/'); $result = $test->getValue(23,0);
工厂模式:
以交通工具为例:要求既可以定制交通工具,又可以定制工具产生的过程
1、定制交通工具
1)定义一个结构,里面包含交通工具的方法(启动、运行、停止)
2)让飞机、汽车等类去实现它们
2、定制通常(与上面的类似)
1)定义一个结构,里面包含交通工具的制造方法(启动、运行、停止)
2)分别写制造飞机、汽车的工厂类去继承实现这个接口
3、观察者模式
观察者模式属于行为模式,是定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖它的对象都得到通知并自动刷新。它完美的将观察者对象和被观察者对象分离。可以在独立的对象(主体)中维护一个对主体感兴趣的依赖项(观察者)列表。让所有观察期各自实现公共的Observer接口,以取消主体和依赖对象之间的直接依赖关系。
用到了SPL(Standard PHP Library)
class MyObserver implements SplObserver { public function update(SplSubject $subject) { echo __CLASS__.'-'.$subject->getName(); } } class MyObserver2 implements SplObserver { public function update(SplSubject $subject) { echo __CLASS__.'-'.$subject->getName(); } } class MySubject implements SplSubject { private $_observers; private $_name; public function __construct($name) { $this->_observers = new SplObjectStorage(); $this->_name = $name; } public function attach(SplObserver $observer) { $this->_observers->attach($observer); } public function detach(SplObserver $observer) { $this->_observers->detach($observer); } public function notify() { foreach($this->_observers as $observer) { $observer->update($this); } } public function getName() { return $this->_name; } } $observer1 = new MyObserver1(); $observer2 = new MyObserver2(); $subject = new MySubject('test'); $subject->attach($observer1); $subject->attach($observer2);
4、策略模式
此模式中,算法是从复杂类中提取的,因而可以方便地替换。例如,如果要更改搜索引擎中排列页的方法,则策略模式是一个不错的选择。思考一下搜索引擎的几个部分--一部分遍历页面,一部分对每页排列,另一部分基于排列的结果排序。在复杂的示例中,这些部分都在同一个类中。通过使用策略模式,可以将排列部分放入另一个类中,以便更改排列的方式,而不影响搜索引擎的其余代码。
作为一个较简单的示例,线面显示了一个用户列表类,它提供了一个根据一组即插即用的策略查找一组用户的方法。
//定义接口 interface IStrategy { function filter($record); } //实现接口方式1 class FindAfterStrategy implements IStrategy { private $_name; public function __construct($name) { $this->_name = $name; } public function filter($record) { return strcmp($this->_name, $record) <= 0; } } //实现结构方式2 class RandomStrategy implements IStrategy { public function filter($record) { return rand(0,1) >= 0.5; } } //主类 class UserList { private $_list = array(); public function __construct($names) { if($names != null) { foreach($names as $name) { $this->list[] = $name; } } } public function add($name) { $this->_list[] = $name; } public function find($filter) { $recs = array(); foreach($this->_list as $user) { if($filter->filter($user)) { $recs[] = $user; } } return $recs; } } $ul = new UserList(array( 'Andy','Jack','Lori','Megan' )); $f1 = $ul->find(new FindAfterStrategy('J')); print_r($f1); $f2 = $ul->find(new RandomStrategy()); print_r($f2);
策略模式非常适合复杂数据管理系统或数据处理系统,二者在数据筛选、搜索或处理的方式方法方面都需要较高的灵活性