简述##
工厂,顾名思义:通过对原材料进行不同的加工来生产不同的品。设计模式里面的简单工厂模式也类似。通过传入的参数来对应创造不同的实例(这些不同实例是属于同一个继承链上的) ,然后返回一个基类的引用(或者指针)。
举例
书读千遍不如实践一次,看着书上的说明好像懂了,但是实际上在自己写程序的时候就混淆或者忘记了。说白了还是不懂,没能把学到的知识结合现实的例子来结合。
这里我举两个我自己想到的例子作为说明跟大家分享一下。
第一个,简易计算器的实现。功能包括加、减、乘、除。
第二个,企业工资计算。企业不同职工工资计算方法是不一样的。从底层工人,到蓝领,白领,金领都不一样。一般来说,这两个例子编程实现起来都相当简单,甚至于我都不想在这里写出来了,包括我之前还没看设计模式的时候,我也是一看了题目就写了代码。因为之前求的是方便,一个简易的计算器,一般来说就从UI层取得计算类型,在代码块中直接’if()\else()’就搞定了。同样来说,企业工资计算也是一样。如果需求不变,运算类型或者职工工种不多的情况下可以这样写,因为简单粗暴。
但是问题是,一旦面临着需求不断变化和类型比较多的情况下,那么上面说的代码就直接是不能用了。我们之前学习面向对象的时候,书上一直强调,三大特性:继承,封装,多态。又说了,一个好的项目或者程序,是要求:易维护、可复用、可扩展、灵活性好。我对它们的理解是:
易维护:要改就只改需要改的地方,各部分耦合度低。()
可复用:代码在各处都能重复使用,有普适性。(封装、模块化)
可扩展:如果需要增加功能,那么尽量在不修改已有代码的情况下。(继承,多态)
灵活性好:通过不同的组合对象、方法,得到不同的功能。(比如装饰模式)
设计模式就是运用面向对象的三大特性:继承、多态、封装,来达到程序的易维护、可复用、可扩展、灵活性好的要求。
因此,我们需要学习设计模式。对于上面的两个问题,可以采用简单工厂、策略、工厂模式来实现。现在,采用简单工厂模式,因为它最简单易懂。分析
既然是面向对象,那么我们就需要运用抽象的思维分析。上面举的两个列子,都有一个共同点,他们都属于同一个业务(或者范畴)。计算器中加、减、乘、除都是属于不同运算类型,但是他们有共同点:参数都是两个,目的都是求出结果;企业工资计算中,不同职工虽然工资计算方式不一样,但是他们的基本信息组成都一样:姓名,学历,基本工资,奖金,出勤率等。因此,他们其实只是实现的方式不一样而已,输入和输出其实都是一样的。
对于计算器,我们可以建立一个运算模板类作为基类,积累提供模板函数和基本属性(运算参数),衍生出加、减、乘、除四个类;一个工厂类作为生产这些类的地方。这样,一个简单工厂模式就出来了。以后如果是哪个运算出问题了,就只要针对哪个类修改就行了;需要加运算,就从模板类再派生一个类就行了;同时运算类的代码到哪里都能够使用;这样,不管有多少种运算类别,都能够很容易解决了。
UML图如下:
一般来说我们一般软件设计采用的方式都是三层架构,分为界面、业务逻辑、数据库访问层;这里由于没有牵扯到数据库,所以就简单分为界面和业务层。结合三层架构,使用工厂模式,我们把计算的过程与界面给分开,把耦合度给降低了。而且这样的逻辑让人一目了然,要增加运算类型只要继承Operator类,然后在工厂类那边增加一个返回实例的代码段就行了。总之呢,方便、简洁,我们写程序最终目的不是完成一个程序,而是完成一个良好的程序。
下面我附上的java实现代码:
package com.malingyi.operator;
import java.util.Scanner;
/**
* UI层,与用户交互的界面
* @author David
*
*/
public class MainUI {
public static void main(String[] args) {
// TODO Auto-generated method stub
double mNumA;
double mNumB;
int type;
Scanner scanner = new Scanner(System.in);
System.out.println("请选择运算类型:\n1:加法 2:减法 3:乘法 4:除法");
type = scanner.nextInt();
System.out.println("请输入第一个参数:");
mNumA = scanner.nextDouble();
System.out.println("请输入第二个参数:");
mNumB = scanner.nextDouble();
Operator operator = Factory.getOprator(type);
operator.setNumA(mNumA);
operator.setNumB(mNumB);
System.out.println("结果是:"+operator.getResult());
}
}
/**
*下面的是业务逻辑层,封装业务逻辑
*/
package com.malingyi.operator;
/**
* 运算基类
* @author David
*
*/
public class Operator {
private double mNumA;
private double mNumB;
public void setNumA(double numA){
mNumA = numA;
}
public void setNumB(double numB){
mNumB = numB;
}
public double getNumA(){
return mNumA;
}
public double getNumB(){
return mNumB;
}
/**
* 计算结果模板
* @return 默认基类返回的结果为 0
* @throws Exception
*/
public double getResult() throws Exception{
double result = 0;
return result;
}
}
package com.malingyi.operator;
/**
* 加法运算类
* @author David
*
*/
public class OperationAdd extends Operator {
@Override
public double getResult() {
// TODO Auto-generated method stub
double result = 0;
result = getNumA()+getNumB();
return result;
}
}
package com.malingyi.operator;
/**
* 减法运算类
* @author David
*
*/
public class OperationSub extends Operator {
@Override
public double getResult() throws Exception {
// TODO Auto-generated method stub
double result = 0;
result = getNumA()-getNumB();
return result;
}
}
package com.malingyi.operator;
/**
* 除法运算类
* @author David
*
*/
public class OperationDiv extends Operator {
@Override
public double getResult() throws Exception {
// TODO Auto-generated method stub
double result = 0;
try {
if(getNumB() == 0){
throw new Exception("除数不能为零");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
result = getNumA()/getNumB();
return result;
}
}
package com.malingyi.operator;
/**
* 乘法运算类
* @author David
*
*/
public class OperationMul extends Operator {
@Override
public double getResult() {
// TODO Auto-generated method stub
double result = 0;
result = getNumA()*getNumB();
return result;
}
}
package com.malingyi.operator;
/**
* 简单工厂类,根据传来的运算类型,产出相应的运算实例
* @author David
*
*/
public class Factory {
public static final int ADD = 1;
public static final int SUB = 2;
public static final int MUL = 3;
public static final int DIV = 4;
/**
* 静态类,用来获取具体运算类
* @param type 运算类的类型。
* @return 与参数对应的运算类类型,如果不存在则返回null
*/
public static Operator getOprator(int type) {
switch (type) {
case ADD:
return new OperationAdd();
case SUB:
return new OperationSub();
case MUL:
return new OperationMul();
case DIV:
return new OperationDiv();
default:
break;
}
return null;
}
}
总结
上面这个例子讲的是计算器的问题,其实企业工资计算也是一样的。这里就不提供UML图和代码了。我的总结就是,简单工厂模式运用了多态、继承、封装,实现了将UI和后台业务逻辑分开,简化开难度。如果几个功能或者业务能够抽象出相同的目标和方法,那么就可以使用简单工厂模式来将具体实现和前台UI分开,降低耦合度。
设计模式也不仅仅是这一种,反正目的就是简化开发难度,达到易维护、可扩展、可复用、灵活性好的目的,量体裁衣才是最好的做法。现在正在学习当中,觉得受益匪浅,所以跟大家分享一下。