簡單工廠
簡單工廠模式又 叫靜態(tài)工廠方法模式(Static FactoryMethod Pattern),是通過專門定義一個(gè)類來負(fù)責(zé)創(chuàng)建其他類的實(shí)例筛欢,被創(chuàng)建的實(shí)例通常都具有共同的父類田藐。
我們從一個(gè)實(shí)例展開
現(xiàn)在有一道面試題:使用java實(shí)現(xiàn)一個(gè)計(jì)算機(jī)控制臺(tái)程序,要求輸入數(shù)的運(yùn)算呕诉,得到結(jié)果。
這道題目最原始的寫法:
public class Computer {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("請(qǐng)輸入第一個(gè)數(shù)字:");
float firstNum = in.nextFloat();
System.out.println("請(qǐng)輸入第二個(gè)數(shù)字:");
float secondNum = in.nextFloat();
System.out.println("請(qǐng)輸入運(yùn)算符號(hào):");
String countQuato = in.next();
if("+".equals(countQuato)){
System.out.println("result : "+(firstNum+secondNum));
}else if("-".equals(countQuato)){
System.out.println("result : "+(firstNum-secondNum));
}else if("*".equals(countQuato)){
System.out.println("result : "+(firstNum*secondNum));
}else if("/".equals(countQuato)){
System.out.println("result : "+(firstNum/secondNum));
}
}
上面的寫法實(shí)現(xiàn)雖然簡單,但是卻沒有面向?qū)ο蟮奶匦云季ǎa拓展性差味咳,顯然不是出題者想要考察的意圖庇勃。
那么面向?qū)ο缶幊桃绾卧陬}中體現(xiàn)呢?
在面向?qū)ο缶幊陶Z言中莺葫,一切都是對(duì)象匪凉,所以上面運(yùn)算符號(hào)也應(yīng)當(dāng)作對(duì)象來處理。
我們首先建立一個(gè)接口
public abstract class Operation {
public abstract float getResult(float firstNumber, float secondNumber);
}
//把符號(hào)都當(dāng)做對(duì)象處理捺檬,實(shí)現(xiàn)此接口
public class AddOperation extends Operation {
@Override
public float getResult(float firstNumber, float secondNumber) {
return firstNumber+secondNumber;
}
}
public class SubOperation extends Operation {
@Override
public float getResult(float firstNumber, float secondNumber) {
return firstNumber-secondNumber;
}
}
public class MulOperation extends Operation {
@Override
public float getResult(float firstNumber, float secondNumber) {
return firstNumber*secondNumber;
}
}
public class DivOperation extends Operation {
@Override
public float getResult(float firstNumber, float secondNumber) {
return firstNumber/secondNumber;
}
}
//接下來需要解決的就是對(duì)象的創(chuàng)建問題了再层,既如何根據(jù)不同的情況創(chuàng)建不同的對(duì)象:我們正好可以通過簡單工廠模式實(shí)現(xiàn)
public class OperationFactory {
public static Operation getOperation(String quotaFlag){
Operation o = null;
switch (quotaFlag){
case "+" : o = new AddOperation();
case "-" : o = new SubOperation();
case "*" : o = new MulOperation();
case "/" : o = new DivOperation();
default:break;
}
return o;
}
}
//調(diào)用:
public class Computer {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("請(qǐng)輸入第一個(gè)數(shù)字:");
float firstNum = in.nextFloat();
System.out.println("請(qǐng)輸入第二個(gè)數(shù)字:");
float secondNum = in.nextFloat();
System.out.println("請(qǐng)輸入運(yùn)算符號(hào):");
String countQuato = in.next();
System.out.println(count(firstNum,secondNum,countQuato));
}
private static float count(float firstNum,float secondNum , String countQuota){
//通過工廠類獲取對(duì)象
Operation operation = OperationFactory.getOperation(countQuota);
return operation.getResult(firstNum,secondNum);
}
}
簡單工廠將對(duì)象的創(chuàng)建過程進(jìn)行了封裝,用戶不需要知道具體的創(chuàng)建過程堡纬,只需要調(diào)用工廠類獲取對(duì)象即可聂受。
這種簡單工廠的寫法是通過switch-case來判斷對(duì)象創(chuàng)建過程的。在實(shí)際使用過程中烤镐,違背了 開放-關(guān)閉原則蛋济,當(dāng)然有些情況下可以通過反射調(diào)用來彌補(bǔ)這種不足。
工廠方法
工廠方法 定義一個(gè)用于創(chuàng)建對(duì)象的接口炮叶,讓子類決定實(shí)例化哪一個(gè)類碗旅,工廠方法使得一個(gè)類的實(shí)例化延遲到了子類
工廠方法在簡單工廠的基礎(chǔ)上再包了一層工廠,所有的工廠都是此工廠的子類镜悉。而產(chǎn)生對(duì)象的類型由子類工廠決定祟辟。使用工廠方法來實(shí)現(xiàn)上面的加減乘除對(duì)象的創(chuàng)建
//定義上級(jí)工廠的接口
public interface IFractory {
public Operation generateOper();
}
//為每一個(gè)類創(chuàng)建工廠
/**
* 工廠方法 為每個(gè)對(duì)象生成一個(gè)工廠類
*/
public class AddOperationFactory implements IFractory{
@Override
public Operation generateOper() {
return new AddOperation();
}
}
public class SubOperationFactory implements IFractory {
@Override
public Operation generateOper() {
return new SubOperation();
}
}
public class MulOperationFactory implements IFractory {
@Override
public Operation generateOper() {
return new MulOperation();
}
}
public class DivOperationFactory implements IFractory {
@Override
public Operation generateOper() {
return new DivOperation();
}
}
//客戶端代碼
IFractory fractory = new AddOperationFactory();
Operation operation = fractory.generateOper();
operation.getResult(firstNum,secondNum);
工廠方法將類的實(shí)例化推遲到了其子類。所以使用工廠方法模式時(shí)侣肄,需要客戶端決定實(shí)例化哪一個(gè)工廠類旧困。選擇判斷問題還是存在的。也就是說,工廠方法把簡單的工廠內(nèi)部邏輯判斷轉(zhuǎn)移到了客戶端來運(yùn)行吼具。你想要加的功能僚纷,本來是要改工廠類的,而現(xiàn)在是修改客戶端拗盒。不過怖竭,我們?cè)谀承┣闆r下通過工廠方法,只需要修改一行實(shí)例化的代碼就可以實(shí)現(xiàn)系統(tǒng)元素的切換(比如切換數(shù)據(jù)源)锣咒。這也是很方便的侵状。
抽象工廠
提供一個(gè)創(chuàng)建一系列相關(guān)相互依賴對(duì)象的接口,而無需指定他們具體的類毅整。抽象工廠為不同產(chǎn)品族的對(duì)象創(chuàng)建提供接口趣兄。
使用場景:系統(tǒng)需要在不同產(chǎn)品族進(jìn)行切換
代碼實(shí)現(xiàn):
public interface IFacfory {
public IUser createUser();
public IDepartment createDepartment();
}
public interface IUser {
public void insert();
public void getById();
}
public interface IDepartment {
public void insert();
public void getDepartmentById();
}
public class SqlServerUser implements IUser {
@Override
public void insert() {
System.out.println("insert into sqlserver.");
}
@Override
public void getById() {
System.out.println("get user by id from sqlserver.");
}
}
public class SqlServerDepartment implements IDepartment {
@Override
public void insert() {
System.out.println("insert department into sqlserver.");
}
@Override
public void getDepartmentById() {
System.out.println("get department in sqlserver by id.");
}
}
public class AccessUser implements IUser {
@Override
public void insert() {
System.out.println("insert into access");
}
@Override
public void getById() {
System.out.println("get by id from access");
}
}
public class AccessDepartment implements IDepartment {
@Override
public void insert() {
System.out.println("insert department into sqlserver.");
}
@Override
public void getDepartmentById() {
System.out.println("get department in sqlserver by id.");
}
}
//不同產(chǎn)品組使用一個(gè)工廠
public class SqlServerFactory implements IFacfory {
@Override
public IUser createUser() {
return new SqlServerUser();
}
@Override
public IDepartment createDepartment() {
return new SqlServerDepartment();
}
}
public class AccessFactory implements IFacfory {
@Override
public IUser createUser() {
return new AccessUser();
}
@Override
public IDepartment createDepartment() {
return new AccessDepartment();
}
}
客戶端:
IFacfory facfory = new AccessFactory();
IUser user = facfory.createUser();
IDepartment department = facfory.createDepartment();
user.insert();
user.getById();
department.insert();
department.getDepartmentById();
抽象工廠最大的好處就是便于交換產(chǎn)品系列,具體工廠在代碼中一般只出現(xiàn)一次悼嫉。這就使得改變應(yīng)用的具體工廠很容易艇潭。
第二個(gè)好處是他能讓具體的創(chuàng)建對(duì)象實(shí)例和客戶端分離,客戶端是通過他們的抽象接口操作實(shí)例
抽象工廠不太易于拓展戏蔑,如果需要自增功能蹋凝,或者自增產(chǎn)品,則需要至少修改三個(gè)類总棵,而且實(shí)例化的代碼是寫死在程序中的 鳍寂, 這樣無法避免違背開放-關(guān)閉原則。
對(duì)于上述問題情龄,可以通過配置文件迄汛,結(jié)合反射的方式來解決。在這里就不再啰嗦