写在前面
一名在校大三学生(双非本科),随时欢迎大家来交流!
从今天起,就要开始学习设计模式了,主要是以《大话设计模式》这本书为主线,利用自己最擅长的java语言来实现,当然书使用C#来实现的【但是我不会C#,所以就用java了】。本来是计划这个学期实习的,但是学校不放。。。
所以就想要学点值钱的东西,没错就是设计模式!!!,当然算法题也会继续刷!!!
然后第一个学习的就是简单工厂设计模式
一、为什么要学习简单工厂设计模式?
话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:“喝酒唱歌,人生真爽。…………”。众文武齐呼:“丞相好诗!”于是一臣子速命印刷工匠刻版印刷,以便流传天下。
样张出来给曹操一看,曹操感觉不妥,说道:“喝与唱,此话过俗,应改为‘对酒当歌’较好!”,于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不喋。只得照办。
可惜三国时期活字印刷还未发明,所以类似事情应该时有发生,如果是有了活字印刷。则只需更改四个字就可,其余工作都未白做。实在妙哉。
- 第一,要改,只需更改要改之字,此为可维护;
- 第二,这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;
- 第三,此诗若要加字,只需另刻字加入即可,这是可扩展;
- 第四,字的排列其实有可能是竖有可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。
而在活字印刷术之前,上面的四种特性都无法满足,要修改,必须重刻,要加字,必须重刻,要重新排列,必须重刻,印完这本书后,此版已无任何可再利用价值。
小时候,我一直奇怪,为何火药、指南针、造纸术都是从无到有,从未知到发现的伟大发明,而活字印刷仅仅是从刻版印刷到活字印刷的一次技术上的进步,为何不是评印刷术为四大发明之一呢?
做了软件开发几年后,经历了太多的客户(曹操)改变需求,更改最初想法的事件,才逐渐明白当中的道理。其实客观的说,客户的要求也并不过份(改几个字而已),但面对已完成的程序代码,却是需要几乎重头来过的尴尬,这实在是痛苦不堪。说白了,原因就是因为我们原先所写的程序,不容易维护,灵活性差,不容易扩展,更谈不上复用,因此面对需求变化,加班加点,对程序动大手术的那种无耐也就非常正常的事了。
之后当我学习了面向对象分析设计编程思想,开始考虑通过封装、继承、多态把程序的耦合度降低(传统印刷术的问题就在于所有的字都刻在同一版面上造成耦合度太高所制),开始用设计模式使得程序更加的灵活,容易修改,并且易于复用。体会到面向对象带来的好处,那种感觉应该就如同是一中国酒鬼第一次喝到了茅台,西洋酒鬼第一次喝到了XO一样,怎个爽字可形容呀。
二、如何利用工厂模式实现一个简单的计算器?
首先,解决这个问题之前,你应该先思考一个问题,代码无错就是优吗?
肯定有同学会说,这个问题太简单了,直接写一个类,然后里面写个 switch 或 if 对元素符号进行判断,然后进行不同的操作【加减乘除】。
确实,这样确实可以实现功能,但是这样不易于维护、复用、扩展、灵活性也不好【结合曹操刻字的案例】,而且也没有用到面向对象的思想【封装、继承、多态】
如何优雅的实现计算器?
-
首先我们一定要松耦合【将公用功能抽离出来】
创建一个公共运算类Operation.java【这里用到了封装】
package com.fafa.designmode.simplefactory; /** * 简易计算器(简单工厂模式) * * @author Sire * @version 1.0 * @date 2022-02-28 23:31 */ public class Operation { private double numberA = 0; private double numberB = 0; public double getNumberA() { return numberA; } public void setNumberA(double numberA) { this.numberA = numberA; } public double getNumberB() { return numberB; } public void setNumberB(double numberB) { this.numberB = numberB; } public double getResult() { double result = 0; return result; } }
-
创建不同的运算类【加减乘除】
记得继承上面的Operation类【面向对象特性:继承】
OperationAdd.java
package com.fafa.designmode.simplefactory.utils; import com.fafa.designmode.simplefactory.Operation; /** * 加法 * * @author Sire * @version 1.0 * @date 2022-02-28 23:35 */ public class OperationAdd extends Operation { @Override public double getResult() { double result = 0; result = this.getNumberA() + this.getNumberB(); return result; } }
OperationSub.java
package com.fafa.designmode.simplefactory.utils; import com.fafa.designmode.simplefactory.Operation; /** * 减法 * * @author Sire * @version 1.0 * @date 2022-02-28 23:38 */ public class OperationSub extends Operation { @Override public double getResult() { double result = 0; result = this.getNumberA() - this.getNumberB(); return result; } }
OperationMul.java
package com.fafa.designmode.simplefactory.utils; import com.fafa.designmode.simplefactory.Operation; /** * 乘法 * * @author Sire * @version 1.0 * @date 2022-02-28 23:49 */ public class OperationMul extends Operation { @Override public double getResult() { double result = 0; result = this.getNumberA() * this.getNumberB(); return result; } }
OperationDiv.java
package com.fafa.designmode.simplefactory.utils; import com.fafa.designmode.simplefactory.Operation; /** * 除法 * * @author Sire * @version 1.0 * @date 2022-02-28 23:49 */ public class OperationDiv extends Operation { @Override public double getResult() { double result = 0; if (0 == this.getNumberB()) { throw new RuntimeException("除数不能为0"); } result = this.getNumberA() / this.getNumberB(); return result; } }
-
然后可以在创建一个工厂类,根据客户端的需求来创建对应的类
这个过程用到了多态【有时一个面向对象的重要特性】
package com.fafa.designmode.simplefactory; import com.fafa.designmode.simplefactory.utils.OperationAdd; import com.fafa.designmode.simplefactory.utils.OperationDiv; import com.fafa.designmode.simplefactory.utils.OperationMul; import com.fafa.designmode.simplefactory.utils.OperationSub; /** * 工厂类 * * @author Sire * @version 1.0 * @date 2022-02-28 23:42 */ public class OperationFactory { public static Operation createOperate(String operate) { Operation operation = null; switch (operate) { case "+": operation = new OperationAdd(); break; case "-": operation = new OperationSub(); break; case "*": operation = new OperationMul(); break; case "/": operation = new OperationDiv(); break; } return operation; } }
-
创建客户端
package com.fafa.designmode.simplefactory; import java.util.Scanner; /** * 计算器客户端 * * @author Sire * @version 1.0 * @date 2022-02-28 23:51 */ public class CalculatorClient { public static void main(String[] args) { Operation operation = null; Scanner sc = new Scanner(System.in); System.out.println("请输入数字A:"); Double numA = sc.nextDouble(); System.out.println("请输入运算符:"); String operate = sc.next(); System.out.println("请输入数字B:"); Double numB = sc.nextDouble(); operation = OperationFactory.createOperate(operate); operation.setNumberA(numA); operation.setNumberB(numB); try { System.out.println("运算结果为:" + operation.getResult()); } catch (Exception e) { System.out.println(e.getMessage()); } } }
三、总结
现在这个程序可以是说很面向对象了,符合上面所说的特性即
- 可维护【即只用该对应功能类即可】
- 可扩展【添加新功能,如开平方,只需加一个类,并修改switch即可】
- 可复用【功能被单独抽离出来了,任何人都可以调用,不用重复写已有功能代码】
- 灵活性好【可以随意修改执行顺序】
编程是一门技术,更是一门艺术