大话设计模式之简单工厂模式
大话设计模式——简单工厂模式
--参考自《大话设计模式》
需求
现在有一个需求,实现一个简单的计算器
对于一般的初学者来说可能会这么实现:
public class calculate {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
System.out.println("请输入数字A:");
String numberA = cin.next();
System.out.println("请输入运算符号(+,-,*,/):");
char op = cin.next().charAt(0);
System.out.println("请输入数字B:");
String numberB = cin.next();
String rst = null;
if(op == '+'){
rst = String.valueOf(Integer.parseInt(numberA)+Integer.parseInt(numberB));
}
if(op == '-'){
rst = String.valueOf(Integer.parseInt(numberA)-Integer.parseInt(numberB));
}
if(op == '*'){
rst = String.valueOf(Integer.parseInt(numberA)*Integer.parseInt(numberB));
}
if(op == '/'){
rst = String.valueOf(Integer.parseInt(numberA)/Integer.parseInt(numberB));
}
System.out.println("结果是: " + rst);
}
}
修改后的版本:
public class calculate2 {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
try {
System.out.println("请输入数字A:");
String numberA = cin.next();
System.out.println("请输入运算符号(+,-,*,/):");
char op = cin.next().charAt(0);
System.out.println("请输入数字B:");
String numberB = cin.next();
String rst = null;
switch (op){
case '+':rst = String.valueOf(Integer.parseInt(numberA)+Integer.parseInt(numberB));break;
case '-':rst = String.valueOf(Integer.parseInt(numberA)-Integer.parseInt(numberB));break;
case '*':rst = String.valueOf(Integer.parseInt(numberA)*Integer.parseInt(numberB));break;
case '/':
if(!numberB.equals("0")){
rst = String.valueOf(Integer.parseInt(numberA)/Integer.parseInt(numberB));
}else{
rst = "除数不能为0!";
}
break;
}
System.out.println("结果是: " + rst);
}catch (Exception e){
System.out.println("您的输入有错:"+e.getMessage());
}
}
}
已经改的不错了,但是这种代码相对来说,可维护性和可扩展性低,如果现在需要重新写一个计算器,那么想一想我们的代码能不能复用呢?
那....Crtl+C和Crtl+V大法呀,多香呀。
有人说初级程序员的工作就是Crtl+C和Crtl+V,其实这是非常不好的编码习惯,想想当你的项目中,重复代码很多的时候,这就是一场灾难,有一个需求发生变化,那么你想想你得修改多少代码?
如果我们能将业务逻辑和客户端代码分开,让他们的耦合度下降,这样才能达到容易维护和扩展的目的。
我们将代码进行修改:
Operation类:
public class Operation {
public static double getResult(double numberA,double numberB,String operate){
double rst = 0.0;
switch (operate.charAt(0)){
case '+':
rst = numberA + numberB;
break;
case '-':
rst = numberA - numberB;
break;
case '*':
rst = numberA * numberB;
break;
case '/':
rst = numberA / numberB;
break;
}
return rst;
}
}
客户端逻辑代码:
public class testOperation {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
try{
System.out.println("请输入数字A:");
String numberA = cin.next();
System.out.println("请输入运算符号(+,-,*,/):");
String op = null;
op = cin.next();
System.out.println("请输入数字B:");
String numberB = cin.next();
System.out.println("结果是: "+ Operation.getResult(Double.parseDouble(numberA),Double.parseDouble(numberB),op));
}catch (Exception e){
System.out.println("您的输入有误:"+e.getMessage());
}
}
}
将业务逻辑和界面逻辑分离开,感觉维护性高多了,卧槽,牛逼呀。
问题又来了,如果现在要增加一个sqrt运算的需求怎么办,如何改?
只要修改Operation类,然后再switch里加一个分支就行了。
就增加了一个功能,就要让其他加减乘除所有的功能都参与运算,如果不小心改到加法运算里了怎么办?如果这是一个公司的计算工资的业务代码,如果参与维护的那个员工有私心,在完成sqrt运算的时候偷偷改了别的代码,改变了自己工资的计算方式,那岂不是风险太大了?
如果我们引入继承和多态,修改一个功能的时候不影响其他功能,这样风险就小很多。
operactionClass计算类:
public abstract class operationClass {
private double number_a = 0;
private double number_b = 0;
public abstract double getResult();
public operationClass() {
}
public double getNumber_a() {
return number_a;
}
public void setNumber_a(double number_a) {
this.number_a = number_a;
}
public double getNumber_b() {
return number_b;
}
public void setNumber_b(double number_b) {
this.number_b = number_b;
}
}
加减乘除类都继承自运算类:
public class operationAdd extends operationClass {
@Override
public double getResult() {
return getNumber_a() + getNumber_b();
}
}
public class operationSub extends operationClass {
@Override
public double getResult() {
return getNumber_a() + getNumber_b();
}
}
public class operationMul extends operationClass{
@Override
public double getResult() {
return getNumber_a() + getNumber_b();
}
}
public class operationDiv extends operationClass{
@Override
public double getResult() throws Exception {
if(getNumber_b() == 0){
throw new Exception("被除数不能为0!");
}
return getNumber_a() + getNumber_b();
}
}
实现了一部分,但是问题来了,我们如果让计算机知道我希望用哪一个算法呢?
简单工厂类##
现在就是到底要实例化谁?将来不会增加实例化的对象,比如增加sqrt功能,这是很容易变化的地方,应该用一个单独的类来做创造实例化的过程,这就是工厂。
简单工厂运算类:
public class operationFactory {
public static operationClass createOperate(String op){
operationClass operation = null;
switch (op.charAt(0)){
case '+':
operation = new operationAdd();
break;
case '-':
operation = new operationSub();
break;
case '*':
operation = new operationMul();
break;
case '/':
operation = new operationDiv();
break;
}
return operation;
}
}
只需要提供符号,就能生产出合适的实例化对象,通过多态,返回父类的方式实现了计算机的结果。
客户端代码实现 测试:
public class test {
@Test
public void testFactory() throws Exception {
operationClass oper;
oper = operationFactory.createOperate("+");
oper.setNumber_a(11);
oper.setNumber_b(22);
System.out.println(oper.getResult());
}
}
通过工厂模式,如果我们要增加复杂的运算,比如开根号,平方运算,只要增加相应的子类并且改造工厂的分支就可以了。这样就实现了业务逻辑和界面逻辑分离,功能模块之间的耦合也降低了。