php面向对象之工厂模式示例

工厂模式是什么?是不是在工厂做事呢?我相信有一些朋友对于php工厂模式还是有一些不理解,下文整理一些关于工厂模式例子.

简单工厂模式:

①抽象基类:类中定义抽象一些方法,用以在子类中实现

②继承自抽象基类的子类:实现基类中的抽象方法

③工厂类:用以实例化对象

php面向对象之工厂模式示例,先看一种代码:

  1. <?php
  2. class Calc{
  3. /**
  4. * 计算结果
  5. *
  6. * @param int|float $num1
  7. * @param int|float $num2
  8. * @param string $operator
  9. * @return int|float
  10. */
  11. public function calculate($num1,$num2,$operator){
  12. try {
  13. $result=0;
  14. switch ($operator){
  15. case '+':
  16. $result= $num1+$num2;
  17. break;
  18. case '-':
  19. $result= $num1-$num2;
  20. break;
  21. case '*':
  22. $result= $num1*$num2;
  23. break;
  24. case '/':
  25. if ($num2==0) {
  26. throw new Exception("除数不能为0");
  27. }
  28. $result= $num1/$num2;
  29. break;
  30. }
  31. return $result;
  32. }catch (Exception $e){
  33. echo "您输入有误:".$e->getMessage();
  34. }
  35. }
  36. }
  37. $test=new Calc();
  38. // echo $test->calculate(2,3,'+');//打印:5
  39. echo $test->calculate(5,0,'/');//打印:您输入有误:除数不能为0
  40. ?>

优点:以上代码使用了面向对象的封装特性,只要有了include这个类,其他页面就可以随便使用了.

缺点:无法灵活的扩展和维护

比如:想要增加一个“求余”运算,需要在switch语句块中添加一个分支语句,代码需要再加一个case进行判断,于是产生了以下问题.

①需要改动原有的代码块,可能会在为了“添加新功能”而改动原有代码的时候,不小心将原有的代码改错了.

②如果要添加的功能很多,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’,或者添加一些程序员专用的计算功能,比如:And, Or, Not, Xor,这样就需要在switch语句中添加N个分支语句,想象下,一个计算功能的函数如果有二三十个case分支语句,代码将超过一屏,不仅令代码的可读性大大降低,关键是,为了添加小功能,还得让其余不相关都参与解释,这令程序的执行效率大大降低.

解决途径:采用OOP的继承和多态思想.

  1. <?php
  2. /**
  3. * 操作类
  4. * 因为包含有抽象方法,所以类必须声明为抽象类
  5. */
  6. abstract class Operation{
  7. //抽象方法不能包含函数体
  8. abstract public function getValue($num1,$num2);//强烈要求子类必须实现该功能函数
  9. }
  10. /**
  11. * 加法类
  12. */
  13. class OperationAdd extends Operation {
  14. public function getValue($num1,$num2){
  15. return $num1+$num2;
  16. }
  17. }
  18. /**
  19. * 减法类
  20. */
  21. class OperationSub extends Operation {
  22. public function getValue($num1,$num2){
  23. return $num1-$num2;
  24. }
  25. }
  26. /**
  27. * 乘法类
  28. */
  29. class OperationMul extends Operation {
  30. public function getValue($num1,$num2){
  31. return $num1*$num2;
  32. }
  33. }
  34. /**
  35. * 除法类
  36. */
  37. class OperationDiv extends Operation {
  38. public function getValue($num1,$num2){
  39. try {
  40. if ($num2==0){
  41. throw new Exception("除数不能为0");
  42. }else {
  43. return $num1/$num2;
  44. }
  45. }catch (Exception $e){
  46. echo "错误信息:".$e->getMessage();
  47. }
  48. }
  49. }
  50. ?>
  51. <?php
  52. /**
  53. * 操作类
  54. * 因为包含有抽象方法,所以类必须声明为抽象类
  55. */
  56. abstract class Operation{
  57. //抽象方法不能包含函数体
  58. abstract public function getValue($num1,$num2);//强烈要求子类必须实现该功能函数
  59. }
  60. /**
  61. * 加法类
  62. */
  63. class OperationAdd extends Operation {
  64. public function getValue($num1,$num2){
  65. return $num1+$num2;
  66. }
  67. }
  68. /**
  69. * 减法类
  70. */
  71. class OperationSub extends Operation {
  72. public function getValue($num1,$num2){
  73. return $num1-$num2;
  74. }
  75. }
  76. /**
  77. * 乘法类
  78. */
  79. class OperationMul extends Operation {
  80. public function getValue($num1,$num2){
  81. return $num1*$num2;
  82. }
  83. }
  84. /**
  85. * 除法类
  86. */
  87. class OperationDiv extends Operation {
  88. public function getValue($num1,$num2){
  89. try { //开源软件:phpfensi.com
  90. if ($num2==0){
  91. throw new Exception("除数不能为0");
  92. }else {
  93. return $num1/$num2;
  94. }
  95. }catch (Exception $e){
  96. echo "错误信息:".$e->getMessage();
  97. }
  98. }
  99. }
  100. ?>

这里采用了面向对象的继承特性,首先声明一个虚拟基类,在基类中指定子类务必实现的方法(getValue()).

分析:通过采用面向对象的继承特性,我们可以很容易就能对原有程序进行扩展,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’等等.

我们只需要另外写一个类(该类继承虚拟基类),在类中完成相应的功能(比如:求乘方的运算),而且大大的降低了耦合度,方便日后的维护及扩展.

现在还有一个问题未解决,就是如何让程序根据用户输入的操作符实例化相应的对象呢?

解决办法:使用一个单独的类来实现实例化的过程,这个类就是工厂.

  1. <?php
  2. /**
  3. * 工程类,主要用来创建对象
  4. * 功能:根据输入的运算符号,工厂就能实例化出合适的对象
  5. *
  6. */
  7. class Factory{
  8. public static function createObj($operate){
  9. switch ($operate){
  10. case '+':
  11. return new OperationAdd();
  12. break;
  13. case '-':
  14. return new OperationSub();
  15. break;
  16. case '*':
  17. return new OperationSub();
  18. break;
  19. case '/':
  20. return new OperationDiv();
  21. break;
  22. }
  23. }
  24. }
  25. $test=Factory::createObj('/');
  26. $result=$test->getValue(23,0);
  27. echo $result;
  28. ?>

我对些的总结就是:根据传递的参数(对象)不同,调用不同的工厂(类),然后用以实现指定的功能,比较大的好处就是简化了以前函数化编程的switch case,if else之类,进行类的分发,不同的东西调用不同的类.