软件设计模式之简单工厂模式
这是我的第一篇文章,而且是第一次使用markdown编辑器,以此记录在编程学习中的一些心得体会,如果有读者看到有不足之处,烦请指出,非常感谢!
背景:楼主是一个渣渣大三狗,这学期学校开了软件设计模式这门课,出于对本门课程的热爱就把所学内容记录下来,而且有幸阅读到程杰老师的名著大话设计模式,甚是喜欢,更给了我好好学下去的动力!
软件设计模式的思想来源于建筑学领域,它包含四个要素:
模式名称: 帮助记忆的名称的专业术语
问题: 设计场景
解决方案: 设计的细节,例如原理图示和代码示例
效果: 设计方案的优缺点,面向软件的一些质量属性,例如可扩展性、复用性等
总结:设计模式可以帮助设计者更快、更好地完成系统的设计工作。
以后所有的代码我都将习惯采用 java语言编写
问: 请用C++、Java、C#或VB、NET任意一种面向对象语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。
一:按照我们平常的编程习惯,肯定是这样写:
import java.util.Scanner;
public class caculator{
public class void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字A");
double numberA = sc,nextDouble();
System.out.println("请输入运算符号:(+、-、*、/):");
String strOperate = sc.next();
System.out.println("请输入数字B");
double numberB = sc,nextDouble();
double result = 0;
switch(strOperate){
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
if(numberB != 0)
result = numberA / numberB;
else
System.out.println("除数不能为0");
break;
}
System.out.println("计算结果为:"+result);
sc.close();
}
}
二:这样从头写到尾就行了吗? 问题来了:上面这段代码并没有题目所要求的的面向对象的思想,而且好的代码一定是要容易维护、容易扩展、容易复用。 那么怎么实现面向对象呢?我们想到了面向对象的三大特性:封装、继承和多态。 那好,接下来我们实现业务的封装,将业务逻辑类和界面逻辑类分离开来:
//运算类
public class Operation{
public static double getResult(double numberA,double numberB,String operate){
double result = 0;
switch(operate){
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
if(numberB != 0)
result = numberA / numberB;
else
System.out.println("除数不能为0");
break;
}
return result;
}
}
//界面类
public class Client{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字A");
double numberA = sc,nextDouble();
System.out.println("请输入运算符号:(+、-、*、/):");
String strOperate = sc.next();
System.out.println("请输入数字B");
double numberB = sc,nextDouble();
double result = getResult(double numberA,double numberB,String operate);
Sysrtem.out.println("计算结果为:"+result);
}
}
三:上面已经将业务和界面分开了,问题又来了:现在如果要添加一个新的开平方根运算呢?我们会想到在switch语句中直接再加一条开平方根的运算不就行了吗?可以是可以,但是这样一来其他代码也参与了编译,而且如果不小心把别的运算在修改的过程中弄错了呢?我们想到把所有的运算都分离了不就行了(使用继承和多态)
//运算主类
public abstract class Operation{
private double numberA;
private double numberB;
public void getNumberA(){
return numberA;
}
public void setNumberA(String numberA){
this.numberA = numberA;
}
public void getNumberB(){
return numberB;
}
public void setNumberB(String numberB){
this.numberB = numberB;
}
public abstract void getResult();
}
//加法
public class OperationAdd extends Operation{
public void getResult(){
double result = getNumberA()+getNumberB();
return result;
}
}
//减法
public class OperationSub extends Operation{
public void getResult(){
double result = getNumberA()-getNumberB();
return result;
}
}
//乘法
public class OperationMul extends Operation{
public void getResult(){
double result = getNumberA()*getNumberB();
return result;
}
}
//除法
public class OperationDiv extends Operation{
public void getResult(){
double result;
if(getNumberB()!=0)
result = getNumberA()/getNumberB();
else
System.out.println("计算结果为:"+result)
return result;
}
}
四:当我们将全部计算分开之后,会发现一个问题,当我们写界面逻辑的时候,我们怎么让计算机知道我们选的是哪一种运算呢?这时候必须要考虑到实例化出一个对象,而且考虑到还会增加别的运算,我们就要单独做一个类用来创造实例,这里我们就要用到—简单工厂模式
//计算工厂类
public class OperationFactory{
public static Operation createOperate(String operate){
Operation oper = null;
switch(Operation){
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
public class Client{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
Operation oper;
System.out.println("请输入运算符号:(+、-、*、/):");
String strOperate = sc.next();
OperationFactory.createOperate(strOperate);
System.out.println("请输入数字A");
oper.setNumberA(sc.nextDouble());
System.out.println("请输入数字B");
oper.setNumberB(sc.next.nextDouble());
oper.getResult();
sc.close();
}
}
总结:
简单工厂方法模式的优点如下:
1:工厂方法包含从一个类的结构中选择初始类的业务逻辑
2:客户类不直接创建产品类的对象,客户类只作为对象的消费者
3:简单工厂方法模式实现了责任分离
4:客户类不负有创建类的对象的责任,因此如果有新的产品子类加入,不必修改已有的客户类代码(前提是客户类暂时不需要使用新的产品子类对象
5:因为工厂类中包含了对象生成的必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,所以客户端类中没有创建对象所需要的条件语句
简单工厂方法模式的缺点如下:
1:由于工厂类必须知道怎样创建每个子类的对象,所以每当增加产品类的时候,都需要工厂类的代码。简单工厂方法模式不符合开闭原则。
2:因为工厂类的工厂方法是静态的,所以工厂类中的方法不能被继承,简单工厂类只能是一个单独的类,而不能成为一个层次的类
(上文总结摘自《软件设计模式与体系结构》)
UML图