最近看了《PHP设计模式》,觉得对自己帮助很大,所有想把该书提到的一些主要设计模式拿出来和大家分享,其中加入自己的理解,希望大家支持。

本系列文章着重介绍设计模式的思想,为了便于读者们的理解,一个设计模式的介绍开始到最后分 三步走:

  1. 问题与解决方案

    从最浅显的需求入手讲解,更好的理解思想以及什么时候使用该设计模式。

  2. UML

    一目了然的看清晰框架(我也是第一次画图,不合理的地方,欢迎指正。)

  3. 代码示例

    对于程序员来说,看代码可能比看枯燥的文字更加理解得快,所有我会用PHP语言写一个完整的简单的实例。

好了,进入正题,这一次我主要写的是  -- 适配器模式

首先,我说说我理解的需要使用适配器模式的假设:

  插线板相信大家都用过,我觉得,它就是我们生活中最好的适配器写照。当然我是说的它的转换插口功能。比如家里墙壁上边的插座都是二孔插座,现在买回一个三孔电器,必须得要三孔插座才行。

  遇到此情况,马上想到三种解决方法:

  1.换墙壁上的插座

  2.换买回来的电器三孔插口

  3.使用插件板,把二孔插座转换成三孔插座

  想想,哪种解决方案最优,最完美。要是你,你会怎么选择?其实在程序中,也有这样子的抉择。

 

  一,问题与解决方案
  在项目最初的代码库中,名为errorObject的对象能够处理所有的错误消息和代码。最初的编程人员并不认为自己的代码会产生任何错误,因此他们设计系统将errorObject对象的错误消息直接输出至控制台。
  下面示例会生成一个“404:Not Found”错误。我们假定错误消息的内容和代码可能变化,但是以文本的方式以及记录格式始终一样。

      

 1     //传统错误处理类
 2     class errorObject{
 3         private $_error;
 4         
 5         public function __construct($error){
 6             $this->_error = $error;
 7         }
 8         
 9         public function getError(){
10             return $this->_error;
11         }
12     }
13     
14     //将错误信息输出到控制台文件
15     class logToConsole{
16         private $_errorObject;
17         
18         public function __construct($errorObject){
19             $this->_errorObject = $errorObject;
20         }
21         
22         public function write(){
23             $erroMsg = $this->_errorObject->getError();
24             echo $erroMsg;
25             file_put_contents('error.log', $erroMsg);
26         }
27     }
28 
29   //创建一个错误对象
30     $error = new errorObject('404: Not Found');
31     //控制台写入日志文件
32     $log = new logToConsole($error);
33     $log->write();

 

在这个场景中,项目中加入了新的网络管理员。建议的最佳做法是安装用于监控软件的网络日志。网络管理员选择的软件包要求将错误日志记录至一个多列的CSV文件。具体的CSV格式要求第一列是错误值代码,第二天应当是错误文本。
选择的新软件包也可使用errorObject类,遗憾的是,版本不同。新的软件包logToCVS类如下:

 1   //检测日志软件要使用 csv格式的错误日志 错误号:解释内容
 2     class logToCSV{
 3         const CSV_FILE_PATH = 'error.csv';
 4         
 5         public function __construct($errorObject){
 6             $this->_errorObject = $errorObject;
 7         }
 8         
 9         //csv 格式 错误号:解释内容
10         public function write(){
11             $erroMsg = $this->_errorObject->getErrorNumber();
12             $erroMsg .= ',';
13             $erroMsg .= $this->_errorObject->getErrorText();
14             echo $erroMsg;
15             file_put_contents(self::CSV_FILE_PATH, $erroMsg);
16         }
17         
18     }

 

针对这个问题,我们可以采用下面两种解决方案:
1.更改现有代码库的errorObject类。
2.创建一个Adapter(适配器)对象。 

考虑到保持errorObject原来标准型的需求,因此创建一个Adapter对象是最佳的解决方案。
新创建的适配器对象中必须存在现有的errorObject的功能性。此外,getErrorNum()和getErrorText()公共方法也必须有。在传统的errorObject类中,getError()方法用户获取错误消息。Adpater(适配器)对象应当利用该方法从父类中获取错误消息,然后再转化输出供给二个新公共方法使用。

 1   //最好的解决方法是,创建一个 csv 的适配器类来处理
 2     class logToCSVAdapter extends errorObject{
 3         private $_errorNumber;
 4         private $_errorText;
 5         
 6         public function __construct($error){
 7             parent::__construct($error);
 8             $parts = explode(':', $this->getError());
 9             $this->_errorNumber = $parts[0];
10             $this->_errorText = $parts[1];
11         }
12         
13         public function getErrorNumber(){
14             return $this->_errorNumber;
15         }
16         
17         public function getErrorText(){
18             return $this->_errorText;
19         }
20     }

 

 

最后,为了实现这个适配器,必须通过使用该适配器替代原来的errorObject来更新代码。这样,logToCSV类就能够接受被适配器的类(而不是原来的errorObject类),从而使原来的代码能够像logToCSV类期望那样运行。

1   //适配器调用代码(实际上就是用子类替代父类,在子类中一系列处理方法)
2     $errorAdapter = new logToCSVAdapter('404:Not Found');
3     $log = new logToCSV($errorAdapter);
4     $log->write();

   二,UML

设计模式之适配器模式 adapter

  三,代码示例

View Code

 1 <?php
 2     //适配器模式
 3     //例1,错误日志处理
 4     
 5     //传统错误处理类
 6     class errorObject{
 7         private $_error;
 8         
 9         public function __construct($error){
10             $this->_error = $error;
11         }
12         
13         public function getError(){
14             return $this->_error;
15         }
16     }
17     
18     //将错误信息输出到控制台文件
19     class logToConsole{
20         private $_errorObject;
21         
22         public function __construct($errorObject){
23             $this->_errorObject = $errorObject;
24         }
25         
26         public function write(){
27             $erroMsg = $this->_errorObject->getError();
28             echo $erroMsg;
29             file_put_contents('error.log', $erroMsg);
30         }
31     }
32     
33     //检测日志软件要使用 csv格式的错误日志 错误号:解释内容
34     class logToCSV{
35         const CSV_FILE_PATH = 'error.csv';
36         
37         public function __construct($errorObject){
38             $this->_errorObject = $errorObject;
39         }
40         
41         //csv 格式 错误号:解释内容
42         public function write(){
43             $erroMsg = $this->_errorObject->getErrorNumber();
44             $erroMsg .= ',';
45             $erroMsg .= $this->_errorObject->getErrorText();
46             echo $erroMsg;
47             file_put_contents(self::CSV_FILE_PATH, $erroMsg);
48         }
49         
50     }
51     
52     //最好的解决方法是,创建一个 csv 的适配器类来处理
53     class logToCSVAdapter extends errorObject{
54         private $_errorNumber;
55         private $_errorText;
56         
57         public function __construct($error){
58             parent::__construct($error);
59             $parts = explode(':', $this->getError());
60             $this->_errorNumber = $parts[0];
61             $this->_errorText = $parts[1];
62         }
63         
64         public function getErrorNumber(){
65             return $this->_errorNumber;
66         }
67         
68         public function getErrorText(){
69             return $this->_errorText;
70         }
71     }
72     
73     //创建一个错误对象
74     $error = new errorObject('404: Not Found');
75     //控制台写入日志文件
76     $log = new logToConsole($error);
77     $log->write();
78     
79     //适配器调用代码(实际上就是用子类替代父类,在子类中一系列处理方法)
80     $errorAdapter = new logToCSVAdapter('404:Not Found');
81     $log = new logToCSV($errorAdapter);
82     $log->write();
83     
84     

   适配器模式大致思想就是这样,代码很简单,也很容易理解。不懂的童鞋可以多看几遍代码,可能更容易理解。下一篇写 -- 建造者模式