现阶段我之所以再次学习设计模式,是因为感受到企业项目的多层封装与调用的复杂性,既然这样那肯定是有自己的设计道理的,能让系统更具有拓展性,安全性,易维护性。所以,我希望这次站在领导设计者的角度去实现功能,而不是简单的增删改查。
现在我们什么都不考虑,仅仅使用Java实现一个计算器
/**
* 简单实现计算器
* 设计:依次输入数字A,运算符号,数字B
*/
public class calculator {
public static void main(String[] args) {
System.out.println("请输入数字A:");
Scanner strNumberA = new Scanner(System.in);
Double numberA = strNumberA.nextDouble();
System.out.println("请选择运算符:+ - * /");
Scanner strOperate = new Scanner(System.in);
String operate = strOperate.next();
System.out.println("请输入数字B:");
Scanner strNumberB = new Scanner(System.in);
double numberB = strNumberA.nextDouble();
//计算
switch(operate){
case "+":
System.out.println(numberA + numberB);
break;
case "-":
System.out.println(numberA - numberB);
break;
case "*":
System.out.println(numberA * numberB);
break;
case "/":
System.out.println(numberA / numberB);
break;
}
}
}
现在我的需求变了,我觉得这个代码中算法和页面混在一起很臃肿。若我需要调整数据展示的样式,就会被看到全部的代码,也不安全。因此我本能的希望可以将这两部分隔开。
那现在就成了这样,一部分负责算法,一部分负责展示。
/**
* 计算部分
*/
public class calculator01 {
public void getOpertion(double numberA,double numberB,String operate){
//计算
switch(operate){
case "+":
System.out.println(numberA + numberB);
break;
case "-":
System.out.println(numberA - numberB);
break;
case "*":
System.out.println(numberA * numberB);
break;
case "/":
System.out.println(numberA / numberB);
break;
}
}
}
public class client {
public static void main(String[] args) {
System.out.println("请输入数字A:");
Scanner strNumberA = new Scanner(System.in);
Double numberA = strNumberA.nextDouble();
System.out.println("请选择运算符:+ - * /");
Scanner strOperate = new Scanner(System.in);
String operate = strOperate.next();
System.out.println("请输入数字B:");
Scanner strNumberB = new Scanner(System.in);
double numberB = strNumberB.nextDouble();
calculator01 calculator01 = new calculator01();
calculator01.getOpertion(numberA, numberB, operate);
}
}
我现在又又有需求了,我希望增加一个开根运算,你会怎么做呢?
是不是在算法类中,switch添加一个开根运算。
不错,但是这样我觉得还是有问题,就是我只让你增加一个开根运算,你就看到了我的其他算法实现(加减乘除),如果你将我的加法修改为减法,这对我也就太不安全了。所以我希望可以将每个算法都隔离开。
那怎么隔离呢?
先观察这些算法的实现,发现有共同点,就是都会传入两个参数。根据面向对象习惯,我打算提取出公共属性。例如,需要加法,我就创建一个名为加法的子类,继承运算类。
/**
* 计算器的公共类:定义参数A,B,和运算结果
*/
public abstract 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 get_NumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
abstract double getResult();
}
/**
* 加法类
*/
public class operationAdd extends Operation{
@Override
double getResult() {
double result = 0;
result = getNumberA() + get_NumberB();
return result;
}
}
/**
* 减法类
*/
public class operationSub extends Operation{
@Override
double getResult() {
double result = 0;
result = getNumberA() - get_NumberB();
return result;
}
}
/**
* 乘法类
*/
public class operationMul extends Operation{
@Override
double getResult() {
double result = 0;
result = getNumberA() * get_NumberB();
return result;
}
}
/**
* 除法类
*/
public class operationDev extends Operation{
@Override
double getResult() {
double result = 0;
//除数不等于0
if(get_NumberB()!= 0){
result = getNumberA() / get_NumberB();
}
return result;
}
}
不错,现在每种算法算法之间都做到了相互隔离,如果我们需要添加一个开根运算,只需要再添加一个类就可以了,这样系统的拓展性就很好。
此刻有一个新的问题,就是我如何调用呢,我如何让计算器知道我使用了哪种算法。
最简单粗暴的方式就是在客户端代码中,写一个switch判断传入的运算符号,创建对应的算法类对象。
可是这样一来,算法类不就又和界面展示混合了,干了半天白费功夫。所以我们希望将创建对应算法类对象的代码单独分离出去。
例如我们希望做减法,那么就传入这个类内部就会调用创建减法类的对象。
这种专门负责创建实例对象的家伙,就跟加工厂一样,因此就提出了简单工厂设计模式的概念。
下面看看代码感受一下吧
public class OperationFactory {
public static Operation creatOperate(String operate){
Operation oper = null;
switch(operate){
case "+":
oper = new operationAdd();
break;
case "-":
oper = new operationSub();
break;
case "*":
oper = new operationMul();
break;
case "/":
oper = new operationDev();
break;
}
return oper;
}
}
public class client {
public static void main(String[] args) {
System.out.println("请输入数字A:");
Scanner strNumberA = new Scanner(System.in);
Double numberA = strNumberA.nextDouble();
System.out.println("请输入数字B:");
Scanner strNumberB = new Scanner(System.in);
double numberB = strNumberB.nextDouble();
System.out.println("请选择运算符:+ - * /");
Scanner strOperate = new Scanner(System.in);
String operate = strOperate.next();
Operation operation = OperationFactory.creatOperate(operate);
operation.setNumberA(numberA);
operation.setNumberB(numberB);
double result = operation.getResult();
System.out.println(result);
}
}
在上述案例中,我们将最开始的一坨代码按照需求,一步步优化解耦(专业名词叫:重构代码),最终分成了多个类。可以发现,最终的代码具有了很好的拓展性和可维护性。在案例中,我们是什么使用了工厂模式呢?是我们依据需求,将算法拆分到最后才考虑到的,并不是生硬的告诉大家直接使用工厂模式。希望大家可以真切的感受到设计模式的魅力。
这只是最初级的一个案例,下一章我们将介绍一个更有特色的案例,更贴近生活。