簡單工廠(SimpleFactory)模式簡介

簡單工廠模式是最簡單的模式了,也是我們打開教材的第一個模式.


一, 簡單工廠模式的定義.

簡單工廠模式是這樣的:


建立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設計模式中, 無論是哪個模式, 實際上都是爲了實現這個原則而存在的.



























發佈了288 篇原創文章 · 獲贊 300 · 訪問量 63萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章