此系列文章为阅读大话设计模式书籍记录的笔记
使用简单工厂模式,利用面向对象的三大特性-【封装】-【继承】-【多态】实现一段计算器代码。下面示例为逐步优化,也可认为是一个初级程序员慢慢优化自己代码的过程。
一:面向过程思想的实现形式
jisuan(1, 2, '/');echo $res;// 此种写法的缺点:不易扩展,没有按业务进行封装,没办法复用// 改进一步,将两个业务逻辑进行封装,可复用的内容进行提炼, 例如计算器分为输入端和计算端
二:使用封装,按照功能模块进行划分,这样较前一种书写形式已经比较好修改代码,寻找功能块了,但是还是很渣
getResult($num1, $num2, $operation); echo $res; }}$a = new Operation();$a->Main(1, 2, '/');// 这仅仅是使用到了面向对象的三个特性,封装,继承,多态中的一个,封装,但是此时耦合度很高,好的程序要做到松耦合,就是修改一个地方,// 并不会影响到现有的功能,如果此处想增加一个开方根运算,紧耦合中必须得更改源代码,松耦合中,新增新的功能不会影响到旧的,所以使用继承的特性
三:上述方法已经使用了封装,但是还是不利于扩展;
如果产品经理说我需要加计算平法的功能进去,那只能是修改switch的功能块,此处因为逻辑简单,可能认为修改会简单些;
但是如果每个计算规则中都需要记录用户的输入信息,存入数据库,存入redis, 然后用一次计算器给加个积分,积分到了哪个级别自动发放礼品等等复杂逻辑进去。
那我心里就会骂这产品瞎改什么需求,当然产品经常改需求很不好,但也有咱们自己的原因,代码写成一大坨,耦合性这么高,找个大牛出来都觉得看的头疼,别说咱们这种渣渣了;
所以此处我们可以想办法把各个运算规则再拆出来,再封装啊。
如果使用面向过程的思想,可以将各个规则分别封装成一个方法,然后用的时候调用就可以了,当然这种也能满足上面描述的情况;
但是如果这些计算规则都具有一定的共性,那么此处使用面向对象的继承更优一些
$name = $value; } public function __get($name) { return $this->$name; } public function getResult() { $res = 0; return $res; }}// 创建加法类class OperationAdd extends Operation{ // 重写getResult方法 public function getResult() { $res = 0; $res = $this->num1 + $this->num2; return $res; }}// 创建减法类class OperationSub extends Operation{ public function getResult() { $res = 0; $res = $this->num1 - $this->num2; return $res; }}// 创建乘法类class OperationMul extends Operation{ public function getResult() { $res = 0; $res = $this->num1 * $this->num2; return $res; }}// 创建除法类class OperationDiv extends Operation{ public function getResult() { if ($this->num2 == 0) { return 'error'; } $res = 0; $res = $this->num1 - $this->num2; return $res; }}$add = new OperationAdd();$add->num1 = 1;$add->num2 = 2;$res = $add->getResult();echo $res;// 此时已经利用面向对象的继承特性,将程序的扩展性能体现出来,如果需要新增一个计算平方的方法,只需要再新增一个类,然后继承自基类就好// 而且并不会影响原有的计算程序, 但是此时存在一个问题,我们需要自己去判断实例化哪个类,那么就需要一个方法去帮我们调度,那此时就可以// 使用第一个设计模式,简单工厂模式,到时候这个方法负责帮我们调度,我们只需将对应参数给其即可
四: 上边使用了,封装,继承,代码已经较为清晰了,如果产品让我加一个计算平方的,那我加上这一个类就好了啊,新加的这个类中只需要写与平方功能有关的代码就行了;
但是此处是我们手动的去调用计算规则的,这样是具有问题的,那就引申出第一个设计模式,简单工厂模式;
说白了,就是建一个类,我们只需要按照规则将参数传进去,这个工厂类自动判断实例化哪个类去,我只关心结果。使用简单工厂模式后,封装性更好了,使用者无需关注内部怎么实现的,
只需要按照指定规则调用就好了,如果想自己扩展,代码结果也很清晰
$name = $value; } public function __get($name) { return $this->$name; } public function getResult() { $res = 0; return $res; }}// 创建加法类class OperationAdd extends Operation{ // 重写getResult方法 public function getResult() { $res = 0; $res = $this->num1 + $this->num2; return $res; }}// 创建减法类class OperationSub extends Operation{ public function getResult() { $res = 0; $res = $this->num1 - $this->num2; return $res; }}// 创建乘法类class OperationMul extends Operation{ public function getResult() { $res = 0; $res = $this->num1 * $this->num2; return $res; }}// 创建除法类class OperationDiv extends Operation{ public function getResult() { if ($this->num2 == 0) { return 'error'; } $res = 0; $res = $this->num1 - $this->num2; return $res; }}// 创建一个工厂类,帮助我们调度程序class OperationFactory{ // 参数检测,调度创建工厂 public function getOperaRes($num1, $num2, $operation) { if (!is_numeric($num1) || !is_numeric($num2)) { return 'num must int'; } if (!$operation) { return 'method must'; } // 调用工厂,工厂生成了模型 $opera = $this->createOperation($operation); $opera->num1 = $num1; $opera->num2 = $num2; $res = $opera->getResult(); return $res; } public function createOperation($operation) { $opera = null; // 简单判断参数 switch ($operation) { case '+': $opera = new OperationAdd(); break; case '-': $opera = new OperationSub(); break; case '*': $opera = new OperationMul(); break; case '/': $opera = new OperationDiv(); break; default: return 'error'; } return $opera; }}$opera = new OperationFactory();$res = $opera->getOperaRes(1, 3, '+');echo $res;// 此处主要体现简单工厂模式的思想,此类还有很多地方需要完善,当然这只是简单的加减乘除,不用工厂模式更加简单,但是计算规则复杂后就体现出封装// 的优越性,产品经理需求变动频繁,经常加功能,该功能就体现出了继承导致松耦合的优越性