说到设计模式,可能大家觉得除了面试的八股文需要,只是简单的背了背,但并不知道为什么要使用。 本文将以一个简单的例子带大家了简单的工厂模式,以及为什么要使用。
假如现在有这么一道题目,让你用任意一种面向对象的语言实现一个计算器控制程序,要求输入两个数和运算符,得到结果
一、初学者的通病:
1、命名不规范
2、分支判断,这样的写法,意味着每个分支都要判断,等于做了三次无用功
3、除数可能为零,导致程序错误
4、大量重复的代码Double.parseDouble()
于是你做了如下修改,将if改成switch,并且引入try catch
public class TestTwo {
public static void main(String[] args) {
try {
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字A: ");
double numberA = Double.parseDouble(sc.nextLine());
System.out.println("请输入运算符号(+、-、*、 /):");
String sign = sc.nextLine();
System.out.println("请输入数字B:");
double numberB = Double.parseDouble(sc.nextLine());
double result = 0d;
switch (sign){
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
result = numberA / numberB;
break;
}
} catch (Exception e){
System.out.println("输入有误:" + e.toString());
}
}
}
这样便解决了代码错误的问题,但工作过的伙伴应该知道,业务总是在不断变化的,如果现在需要你做出一个windows的计算机程序呢,
或许你想着是直接将代码复制过去,改动不大,但这并不是好的习惯,当系统代码的重复度过高,后期维护将是一场灾难。所以接下来我们应该将程序拆分,封装。
二、业务的封装
想想看,之前写的这些代码,有哪些是和控制台无关的,只是和计算器有关?我们可以让业务逻辑与界面逻辑分开,让他们之间的耦合度下降,只有分离开,才可以达到容易维护与拓展。
1、运算类
public class Operation {
public static double getResult(double numberA, double numberB, String sign){
double result = 0d;
switch (sign){
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
result = numberA / numberB;
break;
}
return result;
}
}
将上述红框代码改为如下
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字A: ");
double numberA = Double.parseDouble(sc.nextLine());
System.out.println("请输入运算符号(+、-、*、 /):");
String sign = sc.nextLine();
System.out.println("请输入数字B:");
double numberB = Double.parseDouble(sc.nextLine());
double result = Operation.getResult(numberA, numberB, sign);
这样就把业务和界面分离了。
目前只用了面向对象特性的其中一种:封装,还有多态和继承
我们接着看,如果现在新增了一个需求,我们需要添加一个指数运算,那很简单啊,直接在Operation类switch加一个分支就好了。
这样会带来一个问题,你只是添加一个指数运算,却要让加减乘除都参与编译,如果你一不小心把这个公共方法该坏了,比如把加改成了减,那岂不糟糕了。打个比方,如果你在维护一个薪资管理系统,原本只有技术人员(月薪)、销售人员(底薪+提成)、老板(年薪+股份)三种算法,现在需要添加一个兼职工作人员(时薪的算法)。按照之前的写法,公司必须把原本的三种运算方法代码都给你,让你修改,如果你不小心把自己的薪资构成改了,那…
所以,我们需要将加减乘除运算分离,修改一个不影响另外几个
利用继承和多态
运算类
public abstract class Operation {
public double getResult(double numberA, double numberB){
return 0d;
}
}
加减乘除类
public class Add extends Operation{
@Override
public double getResult(double numberA, double numberB) {
return numberA + numberB;
}
}
public class Sub extends Operation{
@Override
public double getResult(double numberA, double numberB) {
return numberA - numberB;
}
}
以此类推。
这样,如果要修改任何一个算法,就不需要提供其他算法的代码了。但问题来了,我们如何让计算器知道我是希望用哪个算法呢?
三、简单工厂模式
上面的问题,也就是实例化哪个对象的问题,我们可以考虑用个单独的类来做这个创造实例的过程,这就是工厂
下面来写一个简单的工厂类
public class OperationFactory {
public static Operation createOperate(String operate) {
Operation oper = null;
switch (operate){
case "+":
oper = new Add();
break;
case "-":
oper = new Sub();
break;
case "*":
oper = new Mul();
break;
case "/":
oper = new Div();
break;
}
return oper;
}
}
界面代码
Operation operate = OperationFactory.createOperate(sign);
double result = operate.getResult(numberA, numberB);
有了工厂模式,如果后续需要修改加法运算,只需要改Add类,如果需要添加其他运算,只需要增加相应的子类,且在工厂中添加对应的分支。
以上的例子比较简单,重点在于理解工厂模式,以及为什么用工厂模式,这个在项目中的维护至关重要。