這片博客我將以一個計算器的例子跟大家分享一下我對簡單工廠模式和工廠方法模式的理解。
計算器中的基本運算有 加、減、乘、除四個。
首先定義一個運算類,類中有numA和numB這兩個需要運算的變量,有一個getResult方法用於獲取運算結果。
public class Operation{
private double numA;
private double numB;
public double getResult(){}
}
其次,定義加、減、乘、除四個實現類分別繼承運算類Operation,並重寫Operation中的getResult方法。
public class OperationAdd extends Operation {
public double getResult(){
double result = 0;
result = numA + numB;
return result;
}
public class OperationSub extends Operation {
public double getResult(){
double result = 0;
result = numA - numB;
return result;
}
public class OperationMul extends Operation {
public double getResult(){
double result = 0;
result = numA * numB;
return result;
}
public class OperationDiv extends Operation {
public double getResult(){
double result = 0;
if (numB == 0)
throw new Exception("除數不能爲0”);
result = numA / numB;
return result;
}
簡單工廠模式的實現方式:需要定義一個簡單工廠類OperationFactory,在工廠類中進行switch分支的判斷。
class OperationFactory{
public static Operation createOperate(String operate)
{
operation oper = null;
switch(operate)
{
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}return oper;
}
}
客戶端調用如下:
Operation oper = OperationFactory.createOperate("+");
oper.numA = 1;
oper.numB = 2;
double result = opper.getResult();
到這裏,簡單工廠模式就完成了,看起來是不是很清晰,很好用,感覺把該封裝的都封裝了?那麼問題來了,現在萬變的客戶提了一個需求:“麻煩給我加一個開根運算”。然後你要怎麼做?你能做的就是添加一個開根的class,然後在簡單工廠類OperationFactory的switch中加一條分支。添加開根的運算類沒有什麼問題,但是在簡單工廠類OperationFactory的switch中加一條分支是不是看起來怪怪的?是的,它違背了上一篇博客分享中的一條原則-開閉原則。開閉原則的原理就是對擴展開放,對修改關閉,而此時,修改了工廠類,就是對修改開放了,因此就不符合開閉原則。開閉原則這個裁判吧簡單工廠模式給pass掉了。所以嚴格來說,簡單工廠模式並不能算23種設計模式中的一種。
簡單工廠方法被pass掉了,那麼一定就會有一個新的方法取代他,這個方法就是偉大的工廠方法模式。我們試着用工廠方法模式再一次對加減乘除運算進行編碼。
工廠方法模式的實現方式:
前面的operation運算類和加、減、乘、除這四個實現類依然不動。我們創建一個工廠接口。
interface IFactory
{
operation CreateOperation();
}
然後分別創建加、減、乘、除四個工廠類實現上面的工廠接口。
class AddFactory implements IFactory{
public Operation createOperation(){
return new OperationAdd();
}
}
class SubFactory implements IFactory{
public Operation createOperation(){
return new OperationSub();
}
}
class MulFactory implements IFactory{
public Operation createOperation(){
return new OperationMul();
}
}
class DivFactory implements IFactory{
public Operation createOperation(){
return new OperationDiv();
}
}
客戶端調用代碼:
IFactory operFactory = new AddFactory();
Operation oper = operFactory.createOperation();
oper.numA = 1;
oper.numB = 2;
double result = oper.getResult();
到這裏,工廠方法類也跟大家分享完了。現在萬變的客戶再讓你增加一個開根的運算,你需要做的是添加一個開根的實現類,然後再增加一個開根的工廠類繼承IFactory工廠接口並實現開根的類。然後通過客戶端調用開根運算即可。這樣只是增加了類,而不會對原有類進行修改。避免之前好用的代碼被修改發生新的bug。滿足了開閉原則。是不是很happy?
最後,還有一個答疑解惑的過程差點遺漏,可能有的小盆宇會問,工廠方法模式,在工廠類中實現了加減乘除的運算類,然後調用工廠類,那麼我們爲什麼不可以直接調用加減乘除的運算類呢?
這個問題其實剛開始我也困惑了一段時間,不過後來在項目開發中我理解了。設計模式舉例一般都會舉一些比較簡單的、邏輯不是很複雜的例子,因爲畢竟設計模式的本意是讓你掌握編程的一種思維,而不是給你普及java的基礎知識。所以舉例的加減乘除計算器運算的邏輯很簡單。但是真正到了項目中,就不是這種簡單的加減乘除了,也許一個類的實現需要準備很多的參數,準備參數的過程需要一些代碼邏輯做支撐。那時候工廠類其實就是對一個類的實例化做了封裝,讓客戶端直接調用工廠類,而不必追究工廠類中到底是如何實例化一個對象的。這其實也是面向對象中的一個特性:封裝。不知道我這麼說小夥伴們會不會理解,歡迎留言。看到必定回覆!