设计模式(一)

设计模式(一)

      我们说在编程中要有面向对象的思维。而如果没有学过设计模式,那么对于面向对象的理解多半都是肤浅和片面的。下面我们通过对设计模式的学习,来加深对面向对象的认识。

      1、简单工厂模式(静态工厂模式)

      属于创建型模式,专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类

  举个栗子,要实现计算器的功能
参考代码如下:
设计模式(一)
  1 <?php
  2 
  3 // 运算类-计算器
  4 class Operation
  5 {
  6     private $_numberA = 0;
  7     private $_numberB = 0;
  8 
  9     public function numberA($value = ‘‘)
 10     {
 11         if (isset($value) && !empty($value)) {
 12             $this->_numberA = $value;
 13             return $this;
 14         }
 15 
 16         return $this->_numberA;
 17     }
 18 
 19     public function numberB($value = ‘‘)
 20     {
 21         if (isset($value) && !empty($value)) {
 22             $this->_numberB = $value;
 23             return $this;
 24         }
 25         return $this->_numberB;
 26     }
 27 
 28     public function getResult()
 29     {
 30         $result = 0;
 31         return $result;
 32     }
 33 
 34 }
 35 
 36 // 加减乘除类
 37 // 加法类,继承运算类
 38 class OperationAdd extends Operation
 39 {
 40     public function getResult()
 41     {
 42         $result = $this->numberA() + $this->numberB();
 43         return $result;
 44     }
 45 }
 46 
 47 // 减法类,继承运算类
 48 class OperationSub extends Operation
 49 {
 50     public function getResult()
 51     {
 52         $result = $this->numberA() - $this->numberB();
 53         return $result;
 54     }
 55 }
 56 
 57 // 乘法类,继承运算类
 58 class OperationMul extends Operation
 59 {
 60     public function getResult()
 61     {
 62         $result = $this->numberA() * $this->numberB();
 63         return $result;
 64     }
 65 }
 66 
 67 // 除法类,继承运算类
 68 class OperationDiv extends Operation
 69 {
 70     public function getResult()
 71     {
 72         if ($this->numberB() == 0) {
 73             throw new Exception("除数不能为0。");
 74         }
 75         $result = $this->numberA() / $this->numberB();
 76         return $result;
 77     }
 78 }
 79 
 80 // 简单工厂模式
 81 class OperationFactory
 82 {
 83     public static function createOperate(string $operate)
 84     {
 85         switch ($operate) {
 86             case "+":
 87                 $oper = new  OperationAdd();
 88                 break;
 89             case "-":
 90                 $oper = new  OperationSub();
 91                 break;
 92             case "*":
 93                 $oper = new  OperationMul();
 94                 break;
 95             case "/":
 96                 $oper = new  OperationDiv();
 97                 break;
 98             default:
 99                 throw new Exception("运算符号必须是+-*/中的其中一个");
100         }
101         return $oper;
102     }
103 }
104 
105 $oper = OperationFactory::createOperate("*");
106 $oper->numberA(2);
107 $oper->numberB(5);
108 echo $oper->getResult();
View Code

     接下来,只需要输入运算符号,工厂就实例化出合适的对象,通过多态,返回父类的方式实现了计算器的结果。

     如果之后,需要增加各种复杂的运算,比如平发根,立方根等,只要增加相应的运算子类,并且还要去修改运算类工厂,在switch中增加分支。

 说明:对于调用工厂的客户端来说实现了开闭原则而工厂本身没有实现开闭原则。后面可以通过反射的机制来解决switch分支的问题。

    2、工厂方法模式

 定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类
还是拿上面实现计算器的功能来举例
参考代码如下:
设计模式(一)
  1 <?php
  2 
  3 // 运算类-计算器
  4 class Operation
  5 {
  6     private $_numberA = 0;
  7     private $_numberB = 0;
  8 
  9     public function numberA($value = ‘‘)
 10     {
 11         if (isset($value) && !empty($value)) {
 12             $this->_numberA = $value;
 13             return $this;
 14         }
 15 
 16         return $this->_numberA;
 17     }
 18 
 19     public function numberB($value = ‘‘)
 20     {
 21         if (isset($value) && !empty($value)) {
 22             $this->_numberB = $value;
 23             return $this;
 24         }
 25         return $this->_numberB;
 26     }
 27 
 28     public function getResult()
 29     {
 30         $result = 0;
 31         return $result;
 32     }
 33 
 34 }
 35 
 36 
 37 // 加减乘除类
 38 
 39 class OperationAdd extends Operation
 40 {
 41     public function getResult()
 42     {
 43         $result = $this->numberA() + $this->numberB();
 44         return $result;
 45     }
 46 }
 47 
 48 class OperationSub extends Operation
 49 {
 50     public function getResult()
 51     {
 52         $result = $this->numberA() - $this->numberB();
 53         return $result;
 54     }
 55 }
 56 
 57 class OperationMul extends Operation
 58 {
 59     public function getResult()
 60     {
 61         $result = $this->numberA() * $this->numberB();
 62         return $result;
 63     }
 64 }
 65 
 66 class OperationDiv extends Operation
 67 {
 68     public function getResult()
 69     {
 70         if ($this->numberB() == 0) {
 71             throw new Exception("除数不能为0。");
 72         }
 73         $result = $this->numberA() / $this->numberB();
 74         return $result;
 75     }
 76 }
 77 
 78 
 79 interface  iFactory
 80 {
 81     public function createOperation();
 82 }
 83 
 84 
 85 // 加法类工厂
 86 class AddFactory implements iFactory
 87 {
 88     public function createOperation()
 89     {
 90         return new OperationAdd();
 91     }
 92 }
 93 
 94 // 减法类工厂
 95 class SubFactory implements iFactory
 96 {
 97     public function createOperation()
 98     {
 99         return new OperationSub();
100     }
101 }
102 
103 // 乘法类工厂
104 class MulFactory implements iFactory
105 {
106     public function createOperation()
107     {
108         return new OperationMul();
109     }
110 }
111 
112 // 除法类工厂
113 class DivFactory implements iFactory
114 {
115     public function createOperation()
116     {
117         return new OperationDiv();
118     }
119 }
120 
121 // 客户端的实现
122 $operFactory=new AddFactory();
123 $oper=$operFactory->createOperation();
124 $oper->numberA(2);
125 $oper->numberB(8);
126 echo $oper->getResult();
View Code

    说明:工厂方法本身是符合开闭原则的,但要说到客户端,客户总得自己决定创建什么样的对象吧,这个在服务端没法帮客户确定,所以客户端代码需要改是不可避免的。

    3、抽象工厂模式 (Abstract Factory)

    提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

设计模式(一)
  1 <?php
  2 
  3 class User
  4 {
  5     private $_id;
  6     private $_name;
  7 
  8     public function id($value = ‘‘)
  9     {
 10         if (isset($value) && !empty($value)) {
 11             $this->_id = $value;
 12             return $this;
 13         }
 14         return $this->_id;
 15     }
 16 
 17     public function name()
 18     {
 19         if (isset($value) && !empty($value)) {
 20             $this->_name = $value;
 21             return $this;
 22         }
 23         return $this->_name;
 24     }
 25 }
 26 
 27 class Department
 28 {
 29     private $_id;
 30 
 31     public function id($value = ‘‘)
 32     {
 33         if (isset($value) && !empty($value)) {
 34             $this->_id = $value;
 35             return $this;
 36         }
 37         return $this->_id;
 38     }
 39 }
 40 
 41 interface iUser
 42 {
 43     public function insert(User $user);
 44 
 45     public function getUser(int $id);
 46 }
 47 
 48 interface iDepartment
 49 {
 50     public function insert(Department $department);
 51 
 52     public function getDepartment(int $id);
 53 }
 54 
 55 class SqlserverUser implements iUser
 56 {
 57     public function insert(User $user)
 58     {
 59         echo "在SQL Server中给User表增加一条记录<br/>";
 60     }
 61 
 62     public function getUser(int $id)
 63     {
 64         echo "在SQL Server中根据ID=" . $id . "得到User表一条记录<br/>";
 65     }
 66 
 67 }
 68 
 69 class AccessUser implements iUser
 70 {
 71     public function insert(User $user)
 72     {
 73         echo "在Access中给User表增加一条记录<br/>";
 74     }
 75 
 76     public function getUser(int $id)
 77     {
 78         echo "在Access中根据ID=" . $id . "得到User表一条记录<br/>";
 79     }
 80 }
 81 
 82 class SqlserverDepartment implements iDepartment
 83 {
 84     public function insert(Department $department)
 85     {
 86         echo "在SQL Server中给Department表增加一条记录<br/>";
 87     }
 88 
 89     public function getDepartment(int $id)
 90     {
 91         echo "在SQL Server中根据ID=" . $id . "得到Department表一条记录<br/>";
 92     }
 93 
 94 }
 95 
 96 class AccessDepartment implements iDepartment
 97 {
 98     public function insert(Department $department)
 99     {
100         echo "在Access中给Department表增加一条记录<br/>";
101     }
102 
103     public function getDepartment(int $id)
104     {
105         echo "在Access中根据ID=" . $id . "得到Department表一条记录<br/>";
106     }
107 }
108 
109 // 抽象工厂模式
110 interface iFactory
111 {
112     public function createUser();
113 
114     public function createDepartment();
115 }
116 
117 class SqlserverFactory implements iFactory
118 {
119     public function createUser()
120     {
121         return new SqlserverUser();
122     }
123 
124     public function createDepartment()
125     {
126         return new SqlserverDepartment();
127     }
128 }
129 
130 class AccessFactory implements iFactory
131 {
132     public function createUser()
133     {
134         return new AccessUser();
135     }
136 
137     public function createDepartment()
138     {
139         return new AccessDepartment();
140     }
141 }
142 
143 
144 // 客户端代码如下:
145 $user = new User();
146 $dep = new Department();
147 $factory = new AccessFactory();
148 // 生成User类的实例
149 $su = $factory->createUser();
150 $su->insert($user);
151 $su->getUser(1);
152 // 生成Department类的实例
153 $depFac = $factory->createDepartment();
154 $depFac->insert($dep);
155 $depFac->getDepartment(1);
View Code

    4、策略模式(strategy)

 定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
设计模式(一)
  1 <?php
  2 
  3 // 现金收费抽象类
  4 abstract class CashSuper
  5 {
  6     public abstract function acceptCash($money);
  7 }
  8 
  9 // 正常收费子类
 10 class CashNormal extends CashSuper
 11 {
 12     public function acceptCash($money)
 13     {
 14         return $money;
 15     }
 16 }
 17 
 18 // 打折收费子类
 19 class CashRebate extends CashSuper
 20 {
 21     private $moneyRebate = 1;
 22 
 23     public function __construct($moneyRebate)
 24     {
 25         $this->moneyRebate = $moneyRebate;
 26     }
 27 
 28     public function acceptCash($money)
 29     {
 30         return $money * $this->moneyRebate;
 31     }
 32 }
 33 
 34 // 返利收费子类
 35 class CashReturn extends CashSuper
 36 {
 37 
 38     private $moneyCondition = 0;
 39     private $moneyReturn = 0;
 40 
 41     public function __construct($moneyCondition, $moneyReturn)
 42     {
 43         $this->moneyCondition = $moneyCondition;
 44         $this->moneyReturn = $moneyReturn;
 45     }
 46 
 47 
 48     public function acceptCash($money)
 49     {
 50         $result = $money;
 51         if ($money >= $this->moneyCondition) {
 52             $result = $money - floor($money / $this->moneyCondition) * $this->moneyReturn;
 53         }
 54         return $result;
 55     }
 56 }
 57 
 58 class CashContext
 59 {
 60     private $cs;
 61 
 62     // 策略模式与简单工厂结合
 63     public function __construct($type)
 64     {
 65         switch ($type) {
 66             case "1":
 67                 // 正常收费
 68                 $this->cs = new CashNormal();
 69                 break;
 70             case "2":
 71                 // 满300返100
 72                 $this->cs = new CashReturn(300, 100);
 73                 break;
 74             case "3":
 75                 //打8折
 76                 $this->cs = new CashRebate(0.8);
 77                 break;
 78             default:
 79                 throw new Exception("该收费类型不存在。");
 80         }
 81     }
 82 
 83     // 获得计算费用的结果
 84     public function getResult($money)
 85     {
 86         return $this->cs->acceptCash($money);
 87     }
 88 }
 89 
 90 // 客户端主要代码
 91 
 92 class Client
 93 {
 94     public function btnClick($type, $money)
 95     {
 96         // 选择所用具体实现的职责由客户端对象承担,并转给策略模式的context对象
 97         $cashContext = new CashContext($type);
 98         return $cashContext->getResult($money);
 99     }
100 }
101 
102 $client = new Client;
103 echo $client->btnClick(3, 1000);
View Code

    5、装饰模式(decorator)

  动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
设计模式(一)
  1 <?php
  2 
  3 
  4 class Person
  5 {
  6     private $name;
  7 
  8     public function __construct($name)
  9     {
 10         $this->name = $name;
 11     }
 12 
 13     public function show()
 14     {
 15         echo "装扮的" . $this->name;
 16     }
 17 
 18 }
 19 
 20 // 服饰类(Decorator)
 21 class Finery extends Person
 22 {
 23     protected $component;
 24 
 25     public function __construct()
 26     {
 27     }
 28 
 29     //打扮
 30     public function decorate(Person $component)
 31     {
 32         $this->component = $component;
 33     }
 34 
 35     public function show()
 36     {
 37         if ($this->component != null) {
 38             $this->component->show();
 39         }
 40     }
 41 }
 42 
 43 // 具体服饰类(ConcreteDecorator)
 44 class TShirts extends Finery
 45 {
 46     public function show()
 47     {
 48         echo "大T恤 ";
 49         parent::show();
 50     }
 51 }
 52 
 53 class BigTrouser extends Finery
 54 {
 55     public function show()
 56     {
 57         echo "垮裤 ";
 58         parent::show();
 59     }
 60 }
 61 
 62 class Sneakers extends Finery
 63 {
 64     public function show()
 65     {
 66         echo "破球鞋 ";
 67         parent::show();
 68     }
 69 }
 70 
 71 class Suit extends Finery
 72 {
 73     public function show()
 74     {
 75         echo "西装 ";
 76         parent::show();
 77     }
 78 }
 79 
 80 class Tie extends Finery
 81 {
 82     public function show()
 83     {
 84         echo "领带 ";
 85         parent::show();
 86     }
 87 }
 88 
 89 class LeatherShoes extends Finery
 90 {
 91     public function show()
 92     {
 93         echo "皮鞋 ";
 94         parent::show();
 95     }
 96 }
 97 
 98 # 客户端代码
 99 $xc = new Person("小菜");
100 echo "第一种装扮:<br>";
101 
102 $pqx = new Sneakers();
103 $kk = new BigTrouser();
104 $dtx = new TShirts();
105 $pqx->decorate($xc);
106 $kk->decorate($pqx);
107 $dtx->decorate($kk);
108 $dtx->show();
109 
110 echo "<hr>";
111 
112 echo "第二种装扮:<br>";
113 $px = new LeatherShoes();
114 $ld = new Tie();
115 $xz = new Suit();
116 $px->decorate($xc);
117 $ld->decorate($px);
118 $xz->decorate($ld);
119 $xz->show();
View Code

    6、建造者模式

 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
设计模式(一)
  1 <?php
  2 
  3 // 产品类,由多个部件组成
  4 class Product
  5 {
  6     public $arr = [];
  7 
  8     public function add(string $part)
  9     {
 10         // 添加产品部件
 11         array_push($this->arr, $part);
 12     }
 13 
 14     public function show()
 15     {
 16         echo "\n产品 创建----";
 17         // 列举所有的产品部件
 18         foreach ($this->arr as $part) {
 19             echo $part;
 20         }
 21     }
 22 }
 23 
 24 // 抽象建造者类:确定产品由两个部件PartA 和 PartB组成,并声明一个得到产品建造后结果的方法getResult
 25 abstract class Builder
 26 {
 27     public abstract function buildPartA();
 28 
 29     public abstract function buildPartB();
 30 
 31     public abstract function getResult();
 32 }
 33 
 34 // 具体建造者类-建造具体的两个部件是部件A和部件B
 35 class ConcreteBuilder1 extends Builder
 36 {
 37     private $product;
 38 
 39     public function __construct(Product $product)
 40     {
 41         $this->product = $product;
 42     }
 43 
 44     public function buildPartA()
 45     {
 46         $this->product->add("部件A");
 47     }
 48 
 49     public function buildPartB()
 50     {
 51         $this->product->add("部件B");
 52     }
 53 
 54 
 55     public function getResult()
 56     {
 57         return $this->product;
 58     }
 59 }
 60 
 61 
 62 class ConcreteBuilder2 extends Builder
 63 {
 64     private $product;
 65 
 66     public function __construct(Product $product)
 67     {
 68         $this->product = $product;
 69     }
 70 
 71     public function buildPartA()
 72     {
 73         $this->product->add("部件X");
 74     }
 75 
 76     public function buildPartB()
 77     {
 78         $this->product->add("部件Y");
 79     }
 80 
 81 
 82     public function getResult()
 83     {
 84         return $this->product;
 85     }
 86 }
 87 
 88 // 指挥者类-用来指挥建造过程
 89 class Director
 90 {
 91     public function construct(Builder $builder)
 92     {
 93         $builder->buildPartA();
 94         $builder->buildPartB();
 95     }
 96 }
 97 
 98 // 客户端代码(客户端不知道具体的建造过程)
 99 $product = new Product();
100 $director = new Director();
101 $b1 = new ConcreteBuilder1($product);
102 $b2 = new ConcreteBuilder2($product);
103 
104 // 指挥者用ConcreteBuilder1的方法来建造产品
105 $director->construct($b1);
106 $p1 = $b1->getResult();
107 $p1->show();
108 
109 // 指挥者用ConcreteBuilder2的方法来建造产品
110 $director->construct($b2);
111 $p2 = $b2->getResult();
112 $p2->show();
View Code

    说明:如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需知道了。

    7、代理模式(proxy)

 为其他对象提供一种代理以控制对这个对象的访问。
设计模式(一)
 1 <?php
 2 
 3 interface iGiveGift
 4 {
 5     public function giveDolls();
 6 
 7     public function giveFlowers();
 8 
 9     public function giveChocolate();
10 }
11 
12 // 追求者类
13 class Pursuit implements iGiveGift
14 {
15     public $mm;
16 
17     public function __construct(SchoolGirl $mm)
18     {
19         $this->mm = $mm;
20     }
21 
22     public function giveDolls()
23     {
24         echo $this->mm->name() . " 送你洋娃娃<br/>";
25     }
26 
27     public function giveFlowers()
28     {
29         echo $this->mm->name() . " 送你鲜花<br/>";
30     }
31 
32     public function giveChocolate()
33     {
34         echo $this->mm->name() . " 送你巧克力<br/>";
35     }
36 }
37 
38 class Proxy implements iGiveGift
39 {
40     public $gg;
41 
42     public function __construct(SchoolGirl $mm)
43     {
44         $this->gg = new Pursuit($mm);
45     }
46 
47     public function giveDolls()
48     {
49         $this->gg->giveDolls();
50     }
51 
52     public function giveFlowers()
53     {
54         $this->gg->giveFlowers();
55     }
56 
57     public function giveChocolate()
58     {
59         $this->gg->giveChocolate();
60     }
61 }
62 
63 // 被追求者类
64 class SchoolGirl
65 {
66     private $name;
67 
68     public function name($value = ‘‘)
69     {
70         if (isset($value) && !empty($value)) {
71             $this->name = $value;
72             return $this;
73         }
74         return $this->name;
75     }
76 }
77 
78 // 客户端调用代码
79 $sc=new SchoolGirl();
80 $sc->name("李娇娇");
81 $proxy=new Proxy($sc);
82 $proxy->giveDolls();
83 $proxy->giveFlowers();
84 $proxy->giveChocolate();
View Code

    8、单例模式(singleton)

 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
设计模式(一)
 1 <?php
 2 
 3 class Single
 4 {
 5     private static $_instance = null;
 6 
 7     // 私有化构造方法
 8     private function __construct()
 9     {
10     }
11 
12     // 私有化克隆方法
13     private function __clone()
14     {
15     }
16 
17     // 提供一个访问它的全局访问点
18     public static function getInstance()
19     {
20         if (!(self::$_instance instanceof self)) {
21             self::$_instance = new self();
22         }
23         return self::$_instance;
24     }
25 
26     public function test()
27     {
28         echo "调试方法成功";
29     }
30 }
31 
32 $single = Single::getInstance();
33 $single->test();
34 $single2 = Single::getInstance();
View Code

    9、观察者模式(observer)

 定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
设计模式(一)
 1 <?php
 2 
 3 // 当用户注册成功时,邮件观察者或短信观察者则收到相应的通知,发送邮件和短信给用户
 4 
 5 // 通知者-用户类
 6 class User implements SplSubject
 7 {
 8     public $name;
 9     public $email;
10     public $mobile;
11     // 当前观察者集合
12     private $observers = [];
13 
14     public function __construct()
15     {
16         $this->observers = new SplObjectStorage();
17     }
18 
19     // 模拟注册
20     public function register($name, $email, $mobile)
21     {
22         $this->name = $name;
23         $this->email = $email;
24         $this->mobile = $mobile;
25 
26         // business handle and register success
27         $reg_result = true;
28         if ($reg_result) {
29             $this->notify(); // 注册成功 所有的观察者将会收到此主题的通知
30             return true;
31         }
32 
33         return false;
34     }
35 
36     public function attach(SplObserver $observer)
37     {
38         $this->observers->attach($observer);
39     }
40 
41     public function detach(SplObserver $observer)
42     {
43         $this->observers->detach($observer);
44     }
45 
46     public function notify()
47     {
48         if ($this->observers) {
49             foreach ($this->observers as $observer) {
50                 $observer->update($this);
51             }
52         }
53     }
54 }
55 
56 class EmailObserver implements SplObserver
57 {
58     public function update(SplSubject $user)
59     {
60         echo "send email to " . $user->email . PHP_EOL;
61     }
62 }
63 
64 class SmsObserver implements SplObserver
65 {
66     public function update(SplSubject $user)
67     {
68         echo "send sms to " . $user->mobile . PHP_EOL;
69     }
70 }
71 
72 // 业务
73 $user = new User();
74 $emailObserver = new EmailObserver();
75 $smsObserver = new SmsObserver();
76 
77 // 添加观察者
78 $user->attach($emailObserver);
79 $user->attach($smsObserver);
80 
81 // 删除Sms 观察者
82 $user->detach($smsObserver);
83 
84 // 根据注册结果通知观察者,观察者做相应的处理
85 $user->register("小明", "123@qq.com", "18502365895");
View Code

   

    参考资料:

    程杰《大话设计模式》

设计模式(一)

上一篇:Leetcode题目总结 剑指 Offer 10- I. 斐波那契数列


下一篇:【手写数字识别】基于matlab CNN网络手写数字识别分类【含Matlab源码 1286期】