目录

5、对象与设计

5.1、面向对象设计和过程式编程

Q:面向对象和传统的过程式编程有声明不同呢?很多人认为不同之处是OOP包含对象?

A:事实上这种说法并不准确,在PHP,你经常发现过程式编程也使用对象,也会出现类中包含过程式代码的情况。类的出现并不能说明使用了面向对象设计,面向对象和过程式一个核心区别是如何分配职责。

example:

  1. //读取key:value
  2. funciton readParams($sourceFile)
  3. {
  4. $params = array();
  5. //code...
  6. return params;
  7. }
  8. function writeParams($params,$sourseFile)
  9. {
  10. //写入文本参数到sourseFile
  11. }
  12. $file = "./xujiajun.txt";
  13. $array['key1'] = "xujiajun";
  14. $array['key2'] = "徐佳军";
  15. writeParams($array,$file);
  16. $output = readParams($file);
  17. print_r($output);

这段代码较为紧凑且容易维护。

现在我们被告知这个工具支持如下所有所示的XML格式:

  1. <params>
  2. <param>
  3. <key>my key</key>
  4. <key>my val</key>
  5. </param>
  6. </params>

如果参数文件以.xml结尾,就应该以XML模式读取参数文件。这个时候,我们有两个办法:
①在控制代码中检查文件的扩展名
②在读写函数中检测

这里我们选择第二种:

  1. function readParams($source)
  2. {
  3. $params = array();
  4. if(preg_match("/\.xml$/i",$source)){
  5. //从source读XML参数
  6. } else {
  7. //从source读文本参数
  8. }
  9. }
  10. function writeParams($params,$sourse)
  11. {
  12. if(preg_match("/\.xml$/i",$source)){
  13. //写入XML参数到$source
  14. } else {
  15. //写入文本参数到$source
  16. }
  17. }

我们在两个函数中都要检测XML的扩展名,这样的重复性代码会产生问题。如果我们还要支持其他格式的参数,就要始终保持readParams()和WriteParams函数的一致性。

那么,我们用类来解决看看:

  1. abstract class ParamHandle
  2. {
  3. protected $source;
  4. protected $params = array();
  5. function __construct($source)
  6. {
  7. $this->source = $source;
  8. }
  9. function addParam($key,$val)
  10. {
  11. $this->params[$key] = $val;
  12. }
  13. function getAllParams()
  14. {
  15. return $this->params;
  16. }
  17. static function getInstance($filename)
  18. {
  19. if(preg_match("/\.xml$/i",$filename)){
  20. return new XmlParamHander($filename);
  21. }
  22. return new TextParamHander($filename);
  23. }
  24. abstract function write();
  25. abstract function read();
  26. }
  27. //Xml
  28. class XmlParamHander extends ParamHander
  29. {
  30. function write()
  31. {
  32. }
  33. function read()
  34. {
  35. }
  36. }
  37. //Text
  38. class TextParamHander extends ParamHander
  39. {
  40. function write()
  41. {
  42. }
  43. function read()
  44. {
  45. }
  46. }

这些类简单地提供了write()和read()方法的实现。每个类都根据适当的文件格式进行读写。

  1. //Xml
  2. $test = ParamHander::getInstance("./xujiajun.xml");
  3. $test->addParam("key1","val1");
  4. $test->write();
  5. //Text
  6. $test = ParamHander::getInstance("./xujiajun.text");
  7. $test->read();
5.2、定义类

定义类的界限往往比我们想象更加困难,特别是系统不断发展时,最好的办法是分清职责。但是注意设计原则并不是一成不变的。

5.3、多态

多态或称“类切面”是面向对象系统的基本特征之一。

example:

  1. //获取摘要
  2. function getSummary()
  3. {
  4. $base = "$this->title: $this->name";
  5. if ($this->type == 'book'){
  6. $base .= 'pageCount: $this->pageNum';
  7. } else if ($this->type = 'cd'){
  8. $base .= 'Playing Time: $this->playLength';
  9. }
  10. }
  11. //写到这里,看出什么来了吗?暗示我们有两个子类原型`CdProduct`和`BookProduct`
5.4、封装

简单来说,封装就是对客户端代码隐藏数据和功能。封装也是面向对象的重要概念之一。

要实现封装,最简单的办法是将属性定义为private或者protected。通过对客户端代码隐藏属性,我们创建了一个接口并防止在偶然情况下污染对象中的数据。

多态是另外一种封装。

5.5、忘记细节

Gang of Four 在《设计模式》总结了这个规则:

为接口而不是实现而编程(Program to interface,not an implementation)