简单工厂模式
相信很多人都听过设计模式吧,但是也只是局限于听说。很多人认为设计模式并没啥用啊(当然也包括我),我自己写的代码也可以完成需求,为啥还要设计模式呢?
在你学习之后会感叹代码还可以这么写,同时也能够更加熟练的运用面向对象的思想。本系列的文章来源于《大话设计模式》,感兴趣的朋友们可以找来阅读一番,很不错的一本书。
直接开始正文吧,我们要实现两个数的运算,用户输入两个数字和一个操作符后,返回运算结果。
相信各位能够很容易实现该代码如下:
public class Program {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数字A:");
String strNumA = scanner.nextLine();
System.out.print("请输入数字B:");
String strNumB = scanner.nextLine();
System.out.println("请输入运算符:");
String strOper = scanner.nextLine();
if("+".equals(strOper)){
System.out.println(Double.parseDouble(strNumA) + Double.parseDouble(strNumB));
}
if("-".equals(strOper)){
System.out.println(Double.parseDouble(strNumA) - Double.parseDouble(strNumB));
}
if("*".equals(strOper)){
System.out.println(Double.parseDouble(strNumA) * Double.parseDouble(strNumB));
}
if("/".equals(strOper)){
System.out.println(Double.parseDouble(strNumA) / Double.parseDouble(strNumB));
}
}
}
但是我们可以发现,该段代码依然有很多问题,如:用户输入非法值时,我们没有进行异常处理;其次,当进行除法运算时,除数为0的话,我们也并没有进行判断;接着不断我输入哪个运算符,四个if语句都执行了,虽然说计算机运算速度,但是我们写出精炼的代码,能够让别人感觉到你的代码水平较高。
改进后的代码如下:
public class Program {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数字A:");
String strNumA = scanner.nextLine();
System.out.print("请输入数字B:");
String strNumB = scanner.nextLine();
System.out.print("请输入运算符:");
String strOper = scanner.nextLine();
try {
double result = 0;
if ("+".equals(strOper)) {
result = Double.parseDouble(strNumA) + Double.parseDouble(strNumB);
}
else if ("-".equals(strOper)) {
result = Double.parseDouble(strNumA) - Double.parseDouble(strNumB);
}
else if ("*".equals(strOper)) {
result = Double.parseDouble(strNumA) * Double.parseDouble(strNumB);
}
else if ("/".equals(strOper)) {
if(Double.parseDouble(strNumB)!=0)
result = Double.parseDouble(strNumA) / Double.parseDouble(strNumB);
else
System.out.println("除数不能为0!");
}else{
System.out.println("请输入指定运算符!");
return;
}
System.out.println("运算结果:"+result);
}catch (NumberFormatException e){
System.out.println("请输入合法值!");
}
}
}
观察上面的代码后,是不是觉得你写的代码已经很完善了,但是这是一个完全面向过程的程序吧。面向对象的三大特征封装、继承、多态好像并没有使用吧。该段程序的耦合度很高,高质量的程序应该是耦合度很低的,所以我们应该将业务逻辑与业务逻辑无关的分离,降低彼此之间的耦合度。
实现代码如下:
public class Operation {
public static double getResult(double numA,double numB,String oper) throws Exception {
double result = 0;
switch (oper){
case "+":
result = numA + numB;
break;
case "-":
result = numA - numB;
break;
case "*":
result = numA * numB;
break;
case "/":
if(numB != 0) {
result = numA / numB;
}else{
throw new Exception("除数不能为0!");
}
break;
default:
throw new Exception("请输入指定运算符!");
}
return result;
}
}
public class Program {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数字A:");
String strNumA = scanner.nextLine();
System.out.print("请输入数字B:");
String strNumB = scanner.nextLine();
System.out.print("请输入运算符:");
String strOper = scanner.nextLine();
try {
double result = Operation.getResult(Double.parseDouble(strNumA),Double.parseDouble(strNumB),strOper);
System.out.println("运算结果:"+result);
}catch (NumberFormatException e){
System.out.println("请输入合法值!");
}
catch (Exception e){
System.out.println(e.getMessage());
}
}
}
如此一来,我们便将调用者与业务逻辑之间进行了解耦和。
但是,如果我们要增加其他运算呢?如求平方根,求次方的话会怎么做?相信大家的想法是在Operation类中增加case语句不就好了吗?但是这样做的话,我们得更改原程序的代码。通常来说,是很忌讳直接去修改原程序的代码。这时,我们就可以运用面向对象的其他特征了。
public abstract class Operation {
public abstract double getResult(double numA,double numB) throws Exception;
}
class OperAdd extends Operation{
@Override
public double getResult(double numA, double numB) {
return numA + numB;
}
}
class OperSub extends Operation{
@Override
public double getResult(double numA, double numB) {
return numA - numB;
}
}
class OperMul extends Operation{
@Override
public double getResult(double numA, double numB) {
return numA * numB;
}
}
class OperDiv extends Operation{
@Override
public double getResult(double numA, double numB) throws Exception {
if(numB == 0)
throw new Exception("除数不能为0!");
return numA / numB;
}
}
我们通过判断运算符的类型,继承父类生成合适的子类对象,利用多态即可。这样的话,当需要其他功能时,我们只需要继续去继承父类即可。而我们生成合适子类的过程中便用到了简单工厂模式。
简单工厂模式示例代码如下:
public class OperFactory {
public Operation createOper(String oper) throws Exception {
Operation operation = null;
switch (oper){
case "+":
operation = new OperAdd();
break;
case "-":
operation = new OperSub();
break;
case "*":
operation = new OperMul();
break;
case "/":
operation = new OperDiv();
break;
default:
throw new Exception("请输入指定运算符");
}
return operation;
}
}
当我们进行运算时,让工厂产生合适的子类对象,这样我们就可以进行运算了。
public class Program {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数字A:");
String strNumA = scanner.nextLine();
System.out.print("请输入数字B:");
String strNumB = scanner.nextLine();
System.out.print("请输入运算符:");
String strOper = scanner.nextLine();
try {
//生成工厂对象
OperFactory factory = new OperFactory();
//生成合适的子类对象
Operation oper = factory.createOper(strOper);
//利用多态进行计算
double result = oper.getResult(Double.parseDouble(strNumA),Double.parseDouble(strNumB));
System.out.println("运算结果:"+result);
}catch (NumberFormatException e){
System.out.println("请输入合法数字!");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
这个OperFactory像不像一个工厂呢?如饮料厂生产饮料,根据用户的需求去生产合适的饮料。
你可能还挺过静态工厂模式,那么什么时静态工厂呢?很简单,不过是将生产子类的方法由对象方法提升至类方法,这样我们就可以不用生成工厂对象,直接通过类去调用该方法即可。
学习了简单工厂模式后,我们总结一下什么时候时候该设计模式,首先对需求进行分习,如上可以分离出一个抽象类:运算类。然后该类的方法在不同的条件下有不同的执行过程。那么,此时我们便可以使用简单工厂模式。
个人博客:https://wshuaigit.github.io