单例设计模式

简介

所谓单例模式,即在应用程序中最多只有该类的一个实例存在,一旦创建,就会一直存在于内存中!
单例设计模式常应用于数据库类设计,采用单例模式,只连接一次数据库,防止打开多个数据库连接。

特点

单例类不能直接实例化创建,而是只能由类本身实例化。因此,要获得这样的限制效果,构造函数必须标记为private,从而防止类被实例化。
需要一个私有静态成员变量来保存类实例和公开一个能访问到实例的公开静态方法。
在PHP中,为了防止他人对单例类实例克隆,通常还为其提供一个空的私有__clone()方法。

使用场景

只实例化一次,内部实例化,对外只有一个开放方法,只能通过调取该方法进行调取实例化对象。数据库连接

例子

  1. <?php
  2. class Database {
  3. private $instance;
  4. private function__construct() {
  5. // Do nothing.
  6. }
  7. private function__clone() {
  8. // Do nothing.
  9. }
  10. public static function getInstance() {
  11. if (!(self::$instance instanceof self)) {
  12. self::$instance = new self();
  13. }
  14. return self::$instance;
  15. }
  16. }
  17. $a = Database::getInstance();
  18. $b = Database::getInstance();
  19. // true var_dump($a === $b);

工厂设计模式

特点

工厂模式提供了通用的方法有助于我们去获取对象,而不需要关心其具体的内在的实现。
使用方法 new实例化类,每次实例化只需调用工厂类中的方法实例化即可。

使用场景

我们举例子,假设矩形、圆都有同样的一个方法,那么我们用基类提供的API来创建实例时,通过传参数来自动创建对应的类的实例,他们都有获取周长和面积的功能。

例子

  1. <?php
  2. interface InterfaceShape
  3. {
  4. function getArea();
  5. function getCircumference();
  6. }
  7. /**
  8. * 矩形
  9. */
  10. class Rectangle implements InterfaceShape
  11. {
  12. private $width;
  13. private $height;
  14. public function __construct($width, $height)
  15. {
  16. $this->width = $width;
  17. $this->height = $height;
  18. }
  19. public function getArea()
  20. {
  21. return $this->width* $this->height;
  22. }
  23. public function getCircumference()
  24. {
  25. return 2 * $this->width + 2 * $this->height;
  26. }
  27. }
  28. /**
  29. * 圆形
  30. */
  31. class Circle implements InterfaceShape
  32. {
  33. private $radius;
  34. function __construct($radius)
  35. {
  36. $this->radius = $radius;
  37. }
  38. public function getArea()
  39. {
  40. return M_PI * pow($this->radius, 2);
  41. }
  42. public function getCircumference()
  43. {
  44. return 2 * M_PI * $this->radius;
  45. }
  46. }
  47. /**
  48. * 形状工厂类
  49. */
  50. class FactoryShape
  51. {
  52. public static function create()
  53. {
  54. switch (func_num_args()) {
  55. case1:
  56. return newCircle(func_get_arg(0));
  57. case2:
  58. return newRectangle(func_get_arg(0), func_get_arg(1));
  59. default:
  60. # code...
  61. break;
  62. }
  63. }
  64. }
  65. $rect =FactoryShape::create(5, 5);
  66. // object(Rectangle)#1 (2) { ["width":"Rectangle":private]=> int(5) ["height":"Rectangle":private]=> int(5) }
  67. var_dump($rect);
  68. echo "<br>";
  69. // object(Circle)#2 (1) { ["radius":"Circle":private]=> int(4) }
  70. $circle =FactoryShape::create(4);
  71. var_dump($circle);

观察者模式

简介

观察者模式是挺常见的一种设计模式,使用得当会给程序带来非常大的便利,使用得不当,会给后来人一种难以维护的想法。

特点

什么是观察者模式?一个对象通过提供方法允许另一个对象即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。观察者模式是一种事件系统,意味着这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;观察者模式为您提供了避免组件之间紧密耦。

使用场景

用户登录,需要写日志,送积分,参与活动 等。可以结合使用消息队列,把用户和日志,积分,活动之间解耦合。

例子

  1. <?php
  2. /*
  3. 观察者接口
  4. */
  5. interface InterfaceObserver
  6. {
  7. function onListen($sender, $args);
  8. function getObserverName();
  9. }
  10. // 可被观察者接口
  11. interface InterfaceObservable
  12. {
  13. function addObserver($observer);
  14. function removeObserver($observer_name);
  15. }
  16. // 观察者抽象类
  17. abstract class Observer implements InterfaceObserver
  18. {
  19. protected $observer_name;
  20. function getObserverName()
  21. {
  22. return $this->observer_name;
  23. }
  24. function onListen($sender, $args)
  25. {
  26. }
  27. }
  28. // 可被观察类
  29. abstract class Observable implements InterfaceObservable
  30. {
  31. protected $observers = array();
  32. public function addObserver($observer)
  33. {
  34. if ($observerinstanceofInterfaceObserver)
  35. {
  36. $this->observers[] = $observer;
  37. }
  38. }
  39. public function removeObserver($observer_name)
  40. {
  41. foreach ($this->observersas $index => $observer)
  42. {
  43. if ($observer->getObserverName() === $observer_name)
  44. {
  45. array_splice($this->observers, $index, 1);
  46. return;
  47. }
  48. }
  49. }
  50. }
  51. // 模拟一个可以被观察的类
  52. class A extends Observable
  53. {
  54. public function addListener($listener)
  55. {
  56. foreach ($this->observersas $observer)
  57. {
  58. $observer->onListen($this, $listener);
  59. }
  60. }
  61. }
  62. // 模拟一个观察者类
  63. class B extends Observer
  64. {
  65. protected $observer_name = 'B';
  66. public function onListen($sender, $args)
  67. {
  68. var_dump($sender);
  69. echo "<br>";
  70. var_dump($args);
  71. echo "<br>";
  72. }
  73. }
  74. // 模拟另外一个观察者类
  75. class C extends Observer
  76. {
  77. protected $observer_name = 'C';
  78. public function onListen($sender, $args)
  79. {
  80. var_dump($sender);
  81. echo "<br>";
  82. var_dump($args);
  83. echo "<br>";
  84. }
  85. }
  86. $a = new A();
  87. // 注入观察者
  88. $a->addObserver(new B());
  89. $a->addObserver(new C());
  90. // 可以看到观察到的信息
  91. $a->addListener('D');
  92. // 移除观察者
  93. $a->removeObserver('B');
  94. // 打印的信息:
  95. // object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } }
  96. // string(1) "D"
  97. // object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } }
  98. // string(1) "D"

适配器模式

特点

将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作。

应用场景

老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。例如:php连接数据库的方法:mysql,,mysqli,pdo,可以用适配器统一

例子

  1. //老的代码
  2. class User {
  3. private $name;
  4. function __construct($name) {
  5. $this->name = $name;
  6. }
  7. public function getName() {
  8. return $this->name;
  9. }
  10. }
  11. //新代码,开放平台标准接口
  12. interface UserInterface {
  13. function getUserName();
  14. }
  15. class UserInfo implements UserInterface {
  16. protected $user;
  17. function __construct($user) {
  18. $this->user = $user;
  19. }
  20. public function getUserName() {
  21. return $this->user->getName();
  22. }
  23. }
  24. $olduser = new User('张三');
  25. echo $olduser->getName()."n";
  26. $newuser = new UserInfo($olduser);
  27. echo $newuser->getUserName()."n";

策略模式

特点

将一组特定的行为和算法封装成类,以适应某些特定的上下文环境。

应用场景

一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有广告位展示不同的广告。

例子

MaleUserStrategy.php

  1. <?php
  2. namespace IMooc;
  3. class MaleUserStrategy implements UserStrategy {
  4. function showAd()
  5. {
  6. echo "IPhone6";
  7. }
  8. function showCategory()
  9. {
  10. echo "电子产品";
  11. }
  12. }

FemaleUserStrategy.php

  1. <?php
  2. namespace IMooc;
  3. class FemaleUserStrategy implements UserStrategy {
  4. function showAd()
  5. {
  6. echo "2017新款女装";
  7. }
  8. function showCategory()
  9. {
  10. echo "女装";
  11. }
  12. }

UserStrategy.php

  1. <?php
  2. namespace IMooc;
  3. interface UserStrategy {
  4. function showAd();
  5. function showCategory();
  6. }
  7. <?php
  8. interface FlyBehavior{
  9. public function fly();
  10. }
  11. class FlyWithWings implements FlyBehavior{
  12. public function fly(){
  13. echo "Fly With Wings \n";
  14. }
  15. }
  16. class FlyWithNo implements FlyBehavior{
  17. public function fly(){
  18. echo "Fly With No Wings \n";
  19. }
  20. }
  21. class Duck{
  22. private $_flyBehavior;
  23. public function performFly(){
  24. $this->_flyBehavior->fly();
  25. }
  26. public function setFlyBehavior(FlyBehavior $behavior){
  27. $this->_flyBehavior = $behavior;
  28. }
  29. }
  30. class RubberDuck extends Duck{
  31. }
  32. // Test Case
  33. $duck = new RubberDuck();
  34. /* 想让鸭子用翅膀飞行 */
  35. $duck->setFlyBehavior(new FlyWithWings());
  36. $duck->performFly();
  37. /* 想让鸭子不用翅膀飞行 */
  38. $duck->setFlyBehavior(new FlyWithNo());
  39. $duck->performFly();