簡單工廠模式是最簡單的模式了,也是我們打開教材的第一個模式.
一, 簡單工廠模式的定義.
簡單工廠模式是這樣的:
建立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
}
@Override
public 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
}
@Override
public 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設計模式中, 無論是哪個模式, 實際上都是爲了實現這個原則而存在的.