简单工厂模式是最简单的模式了,也是我们打开教材的第一个模式.
一, 简单工厂模式的定义.
简单工厂模式是这样的:
建立1个工厂类, 这个类有1个静态方法, 根据条件(参数)的不同返回不同的同1个类族的对象.
也就是工厂的产品是对象.
但是这种些对象可以属于不同的类,
但是它们的类通常是属于同一超类或实现同一 接口的子类.
比如: 1个工厂类F, 它有1个静态方法getObj(有参数)
getObj可以返回类A1的对象a1, 也可以返回类A2 的对象a2. 但是通常A1 和 A2属于同1个类A.
二, 简单工厂模式的意义.
这里先写个总结. 后面再举例子详细解释
意义就是.
根据上面的例子
1. 当你让程序猿修改类A1, 不会暴露A2的代码. 方便项目管理
2. 当你想添加业务时, 只需要增加子类A3, 不用修改上层A的代码. 方便扩展
(项目中上层类可能用jar包发布, 或者你没有权限)
三, 例子
这个例子很简单, 就是做1个简单的计算器, 只有加法和剪发. 界面大概是这样的:
简单来讲, 就是让User输入2个integer, 然后按button + 就是显示和, 按button "-" 就显示差
3.1 不使用任何模式
当然, 业务和界面代码分开是最基本的要求.
有些人是这样写的:
业务类: Operator1
public class Operation1 {private int i;private int j;public Operation1(int i, int j){this.i = i;this.j = j;}private int add(){return i + j;}private int del(){return i - j;}public int getResult(String symbol){switch(symbol){case "+": return add();case "-": return del();}return 0;}
}
界面代码是这样的:
private void BtnClicked_btnDel(){int i = Integer.parseInt(tb_i.getText());int j = Integer.parseInt(tb_j.getText());lblResult.setText("" + new Operation1(i,j).getResult("-"));}
}
private void BtnClicked_btnAdd(){int i = Integer.parseInt(tb_i.getText());int j = Integer.parseInt(tb_j.getText());lblResult.setText("" + new Operation1(i,j).getResult("+"));}
}
上面的写法是可行的. 但是扩展性不好.
假如我想增加1个button "*" 乘法, 那么我们必须修改类Operation1 添加1个方法mul(),(以及getResult())
这就导致两个问题.
1.暴露了加法和减法是如何实现的.
2. 有可能Operation类不能修改.
3.2 使用简单工厂(SimpleFactory)模式
定义1个抽象超类 Operation
public abstract class Operation {private int i;private int j;public int getI(){return i;}public int getJ(){return j;}public Operation(int i, int j){this.i = i;this.j = j;}public abstract int getResult();
}
那么它的子类就必须重写getResult方法.
定义加法类. OperationAdd
public class OperationAdd extends Operation{public OperationAdd(int i, int j) {super(i, j);// TODO Auto-generated constructor stub}@Overridepublic int getResult(){return this.getI() + this.getJ();}
}
减法类OperationDel
public class OperationDel extends Operation{public OperationDel(int i, int j) {super(i, j);// TODO Auto-generated constructor stub}@Overridepublic int getResult(){return this.getI() - this.getJ();}
}
好了, 这是再定义1个工厂类, 这个工厂的产品就是Operation的子类对象.
public class OperationFactory {public static Operation getOperationObj(int i, int j, String symbol){switch(symbol){case "+": return new OperationAdd(i, j);case "-": return new OperationDel(i, j);}return null;}
}
客户端关键代码:
private void BtnClicked_btnDel(){int i = Integer.parseInt(tb_i.getText());int j = Integer.parseInt(tb_j.getText());Operation oper = OperationFactory.getOperationObj(i,j,"-");lblResult.setText("" + oper.getResult());}
UML:
咋一看, 这里用到4个类, 分别是1个超类, 1个加法类, 1个减法类, 一个工厂类. 貌似更加复杂啦.
但是, 实际上它的可扩展性更好.
首先, 修改减法类, 不会暴露加法类.
其次, 很方便地增加乘法功能. 只需增加1个乘法类, 及修改工厂类. 即使其他3个类用jar包发布也没关系, 根本没必要修改它们.
四, 开放-封闭原则(open-closed principle)
有人问, 貌似在方法1里Operation1类里增加1个乘法方法不是更加方便吗?
方法2里需要增加1个新的类啊.
先不考虑你能不能修改基类的问题.
就如数据库表设计一样, 范式越高, 表就被分割得越多.
增加业务的话, 增加表是优于修改旧表(增加列)的.
设计模式同样, 如果要增加功能, 增加1个类, 比修改旧类要好.
因为这符合开放封闭原则.
所谓开放-封闭原则就是, 对扩展开放, 对修改封闭.
程序猿在做prj时, 往往做到大半时, 遇到User改需求了, 虽然需求改动看起来很小, 实际上对程序影响很大, 甚至要重新翻工.
发生这种痛苦的事情就是在程序设计时对扩展性考虑得不足.
在理想状态下, 我们做设计时, 尽量做到客户无论怎样修改或添加需求.
我们原来的代码(基类)都不用修改, 只需增加新的代码(新的子类)就ok了, 也就是让新代码去完成新的功能.
这就是所谓的开放-封闭原则. 在java设计模式中, 无论是哪个模式, 实际上都是为了实现这个原则而存在的.