什么是设计模式?设计模式的好处
设计模式(Design Patterns),就是设计过程中可以反复使用的、可以解决特定问题的设计方法。
在软件领域,GOF(“四人帮”)首次系统化地提出了3大类(创建模式、行为模式、组合模式)共23种经典的,可以解决常见软件设计问题的可复用设计方案,为可复用软件设计奠定了一定的理论基础。
其实说明白了,设计模式就是说从代码的设计中提取出一些好的设计思想,实现代码的高内聚,低耦合,可复用的特性,也就是说模块间的内聚性高了,同时模块间的耦合度低了,那么在重用代码或者移植代码时将会更加轻松。
其实我们在编程过程中很多时候都是用到了设计模式的,只是我们不清楚,这里提出来,会让你更加的清晰认识什么是面向对象,封装,继承,多态等。
当然现在的技术发展那么快,设计模式已经不再局限于这23种了,还有很多新的设计模式出现,但是我这里就先不说了,还是先从经典开始,经典能成为经典毕竟是有一些道理的,废话不多说,进入正题。
代码无错便是优?
在我刚刚做软件开发的时候,通常的原则就是能够快速完成任务,不出错就是完美的,因此一个功能或许就一个类,一个方法就写了,那么当我想要重新复制这个功能,修改一点东西的时候,就必须全部复制下来,然后修改一点,这样其实有很多的冗余代码,这里大家可能印象还不够直观,我们用代码来说明一下(这里思路参考《大话设计模式》)。
当我们想要实现一个简单的计算器的时候,最基本的方法应该是加减乘除对吧,那么我们这里就来实现一下:
public class Design {
@SuppressWarnings("resource")
public static void main(String args[]) {
System.out.println("请输入数学表达,每输入一个字符回车确认");
Scanner scanner = new Scanner(System.in);
double numA = scanner.nextDouble();
String operate = scanner.next();
double numB = scanner.nextDouble();
double result = 0;
switch (operate) {
case "+":
result = numA + numB;
break;
case "-":
result = numA - numB;
break;
case "*":
result = numA * numB;
break;
case "/":
if (numB == 0) {
try {
throw new Exception("被除数不能为0");
} catch (Exception e) {
e.printStackTrace();
}
}
result = numA / numB;
break;
}
System.out.println("= " + result);
}
}
运行结果:
上面的程序是个最简单的运算程序,看来好像没什么大的问题,但是假如这里需要增加开方的功能,那么你必须又去改核心代码;假如又要增加平方的功能,你又必须改核心源代码,这样改着改着很容易就增加一堆代码,揉在一起变成了几千行,几万行,假如以后你离职了,有人来接手你的代码,看着这些代码,我的天哪,别人看着只有说不敢动,不敢动。。。很多祖传代码也就是这样诞生的。
同时最重要的问题是上面代码是面向过程编码,就是按照我们常规的计算逻辑来的,满足了我们当前的需求,但是不容易维护,不容易扩展,更不容易复用,而且忽视了java很重要的一个思想:面对对象编程,你的对象呢?
面向对象编程
你想假如我们把操作的方法改成一个操作类,然后再分离一个操作客户端出来是不是会好很多呢?就是将业务逻辑与界面逻辑分开来,让代码之间的耦合度下降,这样才能够便于扩展。
如下所示:
操作类
public class Operate {
public Double getRequest(Double numA, Double numB, String operate) {
double result = 0;
switch(operate) {
case "+":
result = numA + numB;
break;
case "-":
result = numA - numB;
break;
case "*":
result = numA * numB;
break;
case "/":
if (numB == 0) {
try {
throw new Exception("被除数不能为0");
} catch (Exception e) {
e.printStackTrace();
}
}
result = numA / numB;
break;
}
return result;
}
}
客户端类:
public class NewClient {
@SuppressWarnings("resource")
public static void main(String args[]) {
System.out.println("请输入数学表达,每输入一个字符回车确认:");
Scanner scanner = new Scanner(System.in);
double numA = scanner.nextDouble();
String operate = scanner.next();
double numB = scanner.nextDouble();
double result = 0;
Operate model = new Operate();
result = model.getRequest(numA, numB, operate);
System.out.println("= " + result);
}
}
运行结果:
这样分开以后对于客户端来说是不是就清爽多了,我不管你是怎么操作的,反正我把值传给操作类对象,然后你再把结果返回给我就行,上面简单的分离代码不但体现了面对对象编程,同时还体现了封装,就是我将操作方法封装起来,你只需要调用就行了,看上面简单的一改就体现了Java的面对对象思想,封装等,而且便于扩展,便于复用,如果你还需要什么其它的客户端操作,你直接重新写个客户端,然后调用操作类方法就行了。
但是上面的代码还是回避不了我们刚才的问题,假如我们要添加开方功能,或者平方功能,那么我们还是要去修改操作类,假如我们在修改的过程中不小心改了加法或者减法的逻辑,别人的在用的时候那就肯定会出问题,那么有没有更好的方法来解决这个问题呢?我们来试试简单工厂模式。
什么是简单工厂模式
简单工厂模式就是将我们需要调用的类交给工厂类来生成,客户端只需要传参数,然后获取最终结果,就像我们把材料交给工厂,然后工厂把最后产品给我们,依然是上面的例子,我们通过代码来看下简单工厂模式:
操作方法实体类:
public class Operation {
private double numA = 0;
private double numB = 0;
public double getNumA() {
return numA;
}
public void setNumA(double numA) {
this.numA = numA;
}
public double getNumB() {
return numB;
}
public void setNumB(double numB) {
this.numB = numB;
}
public double getResult() {
double result = 0;
return result;
}
}
加法类继承操作类:
public class OperationAdd extends Operation {
@Override
public double getResult() {
double result = getNumA() + getNumB();
return result;
}
}
减法类继承操作类:
public class OperationDelete extends Operation {
@Override
public double getResult() {
double result = getNumA() - getNumB();
return result;
}
}
工厂类:
public class OperationFactory {
public static Operation create(String operate) {
Operation opera = null;
switch (operate) {
case "+":
opera = new OperationAdd();
break;
case "-":
opera = new OperationDelete();
break;
default:
opera = null;
}
return opera;
}
}
客户端类:
public class Client {
@SuppressWarnings("resource")
public static void main(String args[]) {
System.out.println("请输入数学表达,每输入一个字符回车确认:");
Scanner scanner = new Scanner(System.in);
double numA = scanner.nextDouble();
String operate = scanner.next();
double numB = scanner.nextDouble();
double result = 0;
Operation op = OperationFactory.create(operate);
op.setNumA(numA);
op.setNumB(numB);
result = op.getResult();
System.out.println("=" + result);
}
}
运行结果:
上面的方法看起来麻烦了很多,但是体现了Java的封装,继承,多态等三大特性,同时还体现了Java的面向对象编程的特点,便于扩展与维护。
不管你有多少操作方法,只需要将具体的操作类继承操作类就行,同时修改一下工厂类就行了,完全不会影响其它的计算类,这个就是设计模式的魅力。