概述
簡單工廠模式(Simple Factory Pattern)是通過專門定義一個工廠類來負責建立其他類的執行個體,被建立的執行個體通常都具有共同的父類。它可以根據參數的不同傳回不同類的執行個體,而無須知道其建立細節。如果在簡單工廠模式中用于建立執行個體的方法是靜态(static)方法,則被稱為靜态工廠方法(Static Factory Method)模式,它不屬于23種設計模式,但在軟體開發中應用也較為頻繁,通常将它作為學習其他工廠模式的入門。其實工廠模式分為了最弱的簡單工廠模式,工廠方法模式,牛逼的抽象工廠模式。
簡單工廠模式結構中包括三種角色:
- 工廠類(Factory):它是簡單工廠模式的核心,負責實作建立所有産品執行個體的内部邏輯;工廠類可以被外界直接調用,建立所需的産品對象;在工廠類中提供了靜态的工廠方法,傳回類型為抽象産品類型。
- 抽象産品(Product):工廠類所建立的所有對象的父類,封裝了各種産品對象的公有方法,它的引入将提高系統的靈活性,使得在工廠類中隻需定義一個通用的工廠方法,因為所有建立的具體産品對象都是其子類對象。
- 具體産品(ConcreteProduct):簡單工廠模式的建立目标,所有被建立的對象都充當這個角色的某個具體類的執行個體。每一個具體産品角色都繼承了抽象産品角色,需要實作在抽象産品中聲明的抽象方法。
執行個體應用
從我的一次面試經曆說起,猶記得當年剛畢業時懷揣着要用代碼拯救世界的夢想,結果現實是無情的,一次次求職碰壁,才發現自己圖樣圖森破,唉,“滿紙荒唐言,一把辛酸淚”,就把我的經曆分享給初出茅廬的學弟們以做警戒吧,面試官給我出了個題目,要求利用一種面向對象的語言實作一個簡單的電腦程式,我心想這不很簡單嗎,馬上就把代碼寫出來,如下:
Scanner scanner=new Scanner(System.in);
System.out.println("請輸入第一個數");
double numA=scanner.nextDouble();
System.out.println("請輸入第二個數");
double numB=scanner.nextDouble();
System.out.println("請輸入運算符");
String operate=scanner.next();
double result=0;
switch (operate){
case "+":
result=numA+numB;
break;
case "-":
result=numA-numB;
break;
case "*":
result=numA*numB;
break;
case "/":
result=numA/numB;
break;
}
System.out.println("最後結果為:"+result);
哈哈,自我感覺良好啊,然後面試官看了看,讓我回去等消息,然後就沒有然後了。。。多年後我才發現,當時是多麼幼稚,看一下代碼,先不說具體的異常處理問題,先說題目的要求——用一種面向對象的語言!我這寫的完全是面向過程的代碼。。。唉,都怨C語言學的太好了,呃~
很多面向對象程式設計的初學者都會有這樣的問題,那就是遇到問題就直覺的用計算機的方式去思考,這樣的思維雖然可以解決問題,但卻使得我們的程式隻滿足目前的需求,程式不容易維護,不容易擴充,更不容易複用。既然認識到問題了,那我們就亡羊補牢吧,下面是我的修改版:
public double getResult(double numberA, double numberB, char operate) {
double result = 0d;
switch (operate) {
case '+':
result = numberA + numberB;
break;
case '-':
result = numberA - numberB;
break;
case '*':
result = numberA * numberB;
break;
case '/':
result = numberA / numberB;
break;
default:
break;
}
return result;
}
代碼功能都實作了,我将業務邏輯封裝到了一個方法裡,使用時直接調用即可,乍一看問題不大,仔細分析,發現還是有很多問題的
緊耦合vs松耦合
面向對象的三大特性:繼承、多态、封裝。我隻用到了一個,倘若我現在要添加取餘運算,怎麼做?直接修改方法嗎?如果一不小心把加号改成減号,那就慘了,這樣的危險我們應該避免,是以最好的辦法是把所有運算都分離出去,讓他們之間互相不受影響,分析一下我們的代碼,其實每種運算都涉及要運算的數和運算符,我們把他抽象出來,将共有特性進行抽象,這其實是為了更好的封裝。
Operation運算類
public abstract class Operation {
public double numberA;
public double numberB;
public abstract double getResult();
}
加減乘除類
public class OperationAdd extends Operation {
public double getResult() {
double result = 0d;
result = numberA + numberB;
return result;
}
}
public class OperationSub extends Operation {
public double getResult() {
double result = 0d;
result = numberA - numberB;
return result;
}
}
剩下的幾個運算類代碼類似,就不寫了
簡單工廠類
public class OperationFactory {
public static Operation createOperate(char 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;
default:
break;
}
return oper;
}
}
使用的時候,我們就可以這樣使用
public static void main(String[] args) {
// TODO Auto-generated method stub
Operation oper;
oper= OperationFactory.createOperate('+');
oper.numberA=5;
oper.numberA=6;
double result=oper.getResult();
}
看下程式的UML類圖:
這樣以來,各個運算類直接就沒有關系了,我們修改某個類也不影響其他類運作,想要添加新的運算也隻是添加運算子類和修改簡單工廠類而已。
總結
簡單工廠模式的主要優點如下:
- 用戶端可以免除直接建立對象的職責,隻關心使用對象,簡單工廠模式實作了對象建立和使用的分離。
- 用戶端不用知道建立産品類具體類名,隻要知道具體産品類所對應的參數即可。
簡單工廠模式的主要缺點如下:
- 工廠類負責所有對象的建立邏輯,該類出問題整個系統挂掉。
- 系統擴充困難,一旦添加新産品就不得不修改工廠邏輯。
- 簡單工廠模式由于使用了靜态工廠方法,是以工廠角色無法形成基于繼承的等級結構。
參考:
http://blog.csdn.net/yanbober/article/details/45312395 http://blog.csdn.net/lmj623565791/article/details/24460585