设计模式也是程序猿的必学技能之一。我粗略的翻了几章以后发现《大话设计模式》这本书写的挺浅显易懂的。于是就决定也连载一下这本书的学习笔记,希望能帮助到大家。大话设计模式学习笔记系列每礼拜一更新一次,看的不过瘾的可以看一下我其他连载的学习笔记呦~~
在这系列的笔记里面,我会照这书本上的方法:先提出一个实际需求问题然后一步一步改善我们的代码,最后根据代码画一张UML图。(作者用的是C#,然而我C#只懂一些皮毛。。(⊙﹏⊙)b,所以我还是用我比较熟悉的java来写样例程序,请见谅呦~)
简单工厂模式
- 提出问题:
编写一个计算类,要求在根据输入的数值和运算符号最后输出计算后的结果。
(大家可以先试着写一下)
第一版问题代码:面向过程
public class Main {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int a = scanner.nextInt();
char x = scanner.next().charAt(0);
int b = scanner.nextInt();
switch (x) {
case '+':
System.out.println(a + b);
break;
case '-':
System.out.println(a - b);
break;
case '*':
System.out.println(a * b);
break;
case '/':
System.out.println(a / b);
break;
default:
break;
}
}
}
}
大家看看自己写的是不是跟上面代码差不多。上述代码从功能上其实说起来完全是没有问题的,因为能够完美实现题目要求。但是由于我们编写的是java代码,就必须要注重“面向对象”这一特点。(上面也写了这个是问题代码)如果这不是一道acm题目,而是公司要求你完成的一个系统,那么就必须要体现面向对象。虽然面向对象写起来代码量一时间会比面向过程多很多,但是面向对象相比于面向过程来说有易维护,易扩展,易复用等优势。大家在平时编程的时候也应该往面向对象方面多思考。好啦大家开始改进我们自己的代码吧,看看能改进到什么地步~
第二版问题代码:没有模块化
public class Main {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int a = scanner.nextInt();
char x = scanner.next().charAt(0);
int b = scanner.nextInt();
Calculate c = new Calculate(a, x, b);
c.result();
}
}
}
class Calculate {
private int a;
private char x;
private int b;
public Calculate(int a, char x, int b) {
this.a = a;
this.x = x;
this.b = b;
}
public void result()
{
switch (x) {
case '+':
System.out.println(a+b);
break;
case '-':
System.out.println(a-b);
break;
case '*':
System.out.println(a*b);
break;
case '/':
System.out.println(a/b);
break;
}
}
}
这一版的问题我写的是没有模块化,是什么意思呢?如果加减乘除是由一个公司的不同部门开发的,也就是说你只负责编写其中的某一块代码比如加法,那么你就不知道其他算法的实现过程,他们是对你保密,同样的你编写的加法也对其他人是保密的。让我们接着来修改代码。
第三版问题代码:仍存在较强耦合
public class Main {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int a = scanner.nextInt();
char x = scanner.next().charAt(0);
int b = scanner.nextInt();
Calculate c;
switch (x) {
case '+':
c = new jia(a,b);
break;
case '-':
c = new jian(a,b);
break;
case '*':
c = new cheng(a,b);
break;
case '/':
c = new chu(a,b);
break;
default:
break;
}
System.out.println(c.result());
}
}
}
interface Calculate
{
int result();
}
class jia implements Calculate
{
private int a;
private int b;
public jia(int a,int b) {
this.a =a;
this.b =b;
}
@Override
public int result() {
return a+b;
}
}
class jian implements Calculate
{
private int a;
private int b;
public jian(int a,int b) {
this.a =a;
this.b =b;
}
@Override
public int result() {
return a-b;
}
}
class cheng implements Calculate
{
private int a;
private int b;
public cheng(int a,int b) {
this.a =a;
this.b =b;
}
@Override
public int result() {
return a*b;
}
}
class chu implements Calculate
{
private int a;
private int b;
public chu(int a,int b) {
this.a =a;
this.b =b;
}
@Override
public int result() {
return a/b;
}
}
代码也简单,所以我就偷一下懒没有写注释~嘿嘿嘿。简单说一下思路:先定义一个算法接口,让所有算法都实现这个接口,这样就实现了不同模块之间的封装。这一版的问题正如我所写的:存在较强耦合性。switch操作不应该在main方法里面执行。
接下来就是我们的重点啦–简单工厂模式。大家通过这一步一步下来也应该能大致猜出来简单工厂模式是干嘛的(定义一个工厂类,然后把第三版main方法里面的switch操作放进工厂,只不过是返回一个类。这样写比较符合“工厂”这个概念)。举个例子:我跟一家制笔厂说:我要钢笔。这个指令发下去,那么制笔厂应该返回给我一个钢笔的对象。其他的同样。
简单工厂类:
class CalculateFactory
{
Calculate calculate;//保存一个Calculate的应用
public Calculate getCalculate(Integer a,char x,int b)
{
switch (x) {
case '+':
calculate = new jia(a, b);
break;
case '-':
calculate = new jian(a, b);
break;
case '*':
calculate = new cheng(a, b);
break;
case '/':
calculate = new chu(a, b);
break;
}
return calculate;//返回经过工厂生产之后的产品
}
}
public class Main {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int a = scanner.nextInt();
char x = scanner.next().charAt(0);
int b = scanner.nextInt();
CalculateFactory cf = new CalculateFactory();
Calculate c = cf.getCalculate(a, x, b);
System.out.println(c.result());
}
}
}
在main方法里只要简单的调用工厂类的getCalculate方法就能返回一个我们想要的对象。
这就是简单工厂模式,相信如果是第一次接触设计模式的朋友们会发出”哇!这个东西有点意思!”的感叹吧。
UML
最后贴一张UML图(Unified Modeling Language)(标准化建模语言),我是在eclipse上用plantuml写的:
uml代码如下:
/**
* @startuml
* class Main {
* +{static}void main(String[] args)
*}
* interface Calculate{
* +{abstract}result():int
* }
* Calculate<|..jia:实现
* class jia{
* -a:int
* -b:int
* +result():int
* }
* Calculate<|..jian:实现
* class jian{
* -a:int
* -b:int
* +result():int
* }
* Calculate<|..cheng:实现
* class cheng{
* -a:int
* -b:int
* +result():int
* }
* Calculate<|..chu:实现
* class chu{
* -a:int
* -b:int
* +result():int
* }
* Calculate<--CalculateFactory:联系
* class CalculateFactory{
* -calculate:Calculate
* +getCalculate(int a,char x,int b):Calculate
* }
* @enduml
*/
下面是uml代码导出来的图,大家看一下。
四个类实现Calculate接口,然后CalculateFactory里面保存Calculate的一个引用,所以是联系关系。
大家有什么问题可以在下面提问呦~~