寫文章的初心主要是用來幫助自己快速的回憶這個模式該怎么用,主要是下面的UML圖可以起到大作用,在你學習過一遍以后可能會遺忘,忘記了不要緊,只要看一眼UML圖就能想起來了。同時也請大家多多指教。
抽象工廠模式(Abstract Factory)
是一種創建型模式。
目錄
一、概述
二、優點
三、舉例
一、概述
1、提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。2、和工廠方法模式不同的是,有多種類型的對象(產品)需要被實例化,同時工廠也被定義了多個不同產品創建的接口。
1.1、主要的角色分兩種,但從代碼(或技術)實現的角度看(為了充分使用面向對象語言的3大特性封裝、繼承、多態,還另外需要抽象類或接口)可能有4個:
- 工廠的抽象類或接口(單個) + 工廠的實現類(多個):控制創建哪些產品以及如何創建產品的類
- 產品的抽象類或接口(多個) + 產品實現類(多個):那些需要被創建(實例化)的類?
1.2、直觀的理解上這些角色之間的關系如下:
1.3、通過技術實現的角度看,對象之間關系的UML圖如下:
?
二、優點
- 使得發起請求的對象和具體創建實例的過程分離
三、舉例
?假設一個部門系統升級,涉及到兩個表:部門表和用戶表。原先這兩表在數據庫A里,升級后新加了個數據庫B,也有部門表和用戶表。現在為了兼容性,A和B兩個庫,和庫里的兩個表(部門表和用戶表)都需要使用。數據庫如下:
3.1、為了實現對不同數據庫的不同表的訪問和連接,分析步驟:
1、分析上述問題:
- 抓住上面關鍵:有兩個數據庫,每個數據庫又有兩個表;
- 兩個數據庫是不同的,但庫里的兩個表是相同的,都是一個用戶表一個部門表;
- 如果把兩個庫同名的表看成一樣,那么邏輯上訪問的就只有兩個表,所以為了實現訪問2個不同表,我們需要定義2個不同的接口,然后針對不同的數據庫,我們還又需要設計不同實現類;
- 我們發現這樣下來會設計很多類,那么在真正使用時需要創建很多不同對象的實例,會比較麻煩,此時就嘗試用抽象工廠模式,將使用和創建分離開來。
2、針對問題的設計要素:
產品的抽象類或接口(多個) + 產品實現類(多個):
- 一個訪問用戶表抽象類或接口;
- 一個訪問部門表抽象類或接口;
- 針對 訪問數據庫A里的用戶表 和 訪問數據庫B里的用戶表 的實現類各一個;
- 針對 訪問數據庫A里的部門表 和 訪問數據庫B里的部門表 的實現類各一個;
工廠的抽象類或接口(單個) + 工廠的實現類(多個):
- 一個用來創建連接數據庫工廠的抽象類或接口;
- 一個用來創建訪問數據庫A的實例對象的工廠;
- 一個用來創建訪問數據庫B的實例對象的工廠。
?(注:先挖個坑,有時候可能不確定應該抽象哪個,那就無腦將那個相對不容易變化的和容易變化的分別抽象出來再進行分析就行。但實際上我相關經驗很少,我也不知道怎么樣才算更好,像本例是將訪問用戶表和訪問部門表抽象出來當接口,但感覺反著來抽象出數據庫A和數據庫B當接口也一樣。具體怎么樣的抽象更好我目前也是菜鳥還不知道該怎么回答,等我以后知道答案了一定會填這個坑的。
不過說這么多,也請大家放心向下看,本例我有借鑒一些教材書,這樣子是沒有問題的。之所以加了這個注,是想到可能有人會想問這個問題,為什么要這樣定義,所以才在此說明。)
?3.2、對象之間的關系用UML圖表示如下:
?
3.3、Java實現代碼如下(建議你在本地試一下,加深印象):
用戶bean(舉例就默認為空了,也不會影響到本例運行):
public class User {//用戶表里的屬性和字段
}
部門bean(舉例就默認為空了,也不會影響到本例運行):
public class Department {//部門表里的屬性和字段
}
訪問用戶表接口:
public interface IUser {public void insertUser(User user);//添加public User selectUserById(int id);//查找
}
?訪問部門表接口:
public interface IDepartment {public void insertDepartment(Department department);//添加public Department selectDepartmentById(int id);//查找
}
用來訪問數據庫A里的用戶表的類:
public class DatabaseAUser implements IUser{@Overridepublic void insertUser(User user) {System.out.println("向數據庫A里的User表中增加一條數據");}@Overridepublic User selectUserById(int id) {System.out.println("根據id查詢數據庫A里的User表中一條數據");return null;}
}
用來訪問數據庫B里的用戶表的類:
public class DatabaseBUser implements IUser{@Overridepublic void insertUser(User user) {System.out.println("向數據庫B里的User表中增加一條數據");}@Overridepublic User selectUserById(int id) {System.out.println("根據id查詢數據庫B里的User表中一條數據");return null;}
}
用來訪問數據庫A里的部門表的類:
public class DatabaseADepartment implements IDepartment {@Overridepublic void insertDepartment(Department department) {System.out.println("向數據庫A里的Department表中增加一條數據");}@Overridepublic Department selectDepartmentById(int id) {System.out.println("根據id查詢數據庫A里的Department表中一條數據");return null;}
}
用來訪問數據庫B里的部門表的類:
public class DatabaseBDepartment implements IDepartment {@Overridepublic void insertDepartment(Department department) {System.out.println("向數據庫B里的Department表中增加一條數據");}@Overridepublic Department selectDepartmentById(int id) {System.out.println("根據id查詢數據庫B里的Department表中一條數據");return null;}
}
?工廠接口:
public interface IFactory {public IUser createUserConnect();//創建User表的訪問連接實例public IDepartment createDepartmentConnect();//創建Department表的訪問連接實例
}
創建數據庫A的訪問實例的工廠:
public class DatabaseAFactory implements IFactory {@Overridepublic IUser createUserConnect() {return new DatabaseAUser();}@Overridepublic IDepartment createDepartmentConnect() {return new DatabaseADepartment();}
}
創建數據庫B的訪問實例的工廠:
public class DatabaseBFactory implements IFactory {@Overridepublic IUser createUserConnect() {return new DatabaseBUser();}@Overridepublic IDepartment createDepartmentConnect() {return new DatabaseBDepartment();}
}
?主程序(發起請求的類):
public class Main {public static void main(String[] args) {User user = new User();Department department = new Department();IFactory factoryA = new DatabaseAFactory();//創建數據庫A連接實例的工廠IUser iUserA = factoryA.createUserConnect();iUserA.insertUser(user);//給數據庫A的用戶表增加數據iUserA.selectUserById(1);//查詢數據庫A的用戶表里的數據IDepartment iDepartmentA = factoryA.createDepartmentConnect();iDepartmentA.insertDepartment(department);//給數據庫A的部門表增加數據iDepartmentA.selectDepartmentById(1);//查詢數據庫A的部門表里的數據System.out.println("==========分界線==========");IFactory factoryB = new DatabaseBFactory();//創建數據庫B連接實例的工廠IUser iUserB = factoryB.createUserConnect();iUserB.insertUser(user);//給數據庫B的用戶表增加數據iUserB.selectUserById(1);//查詢數據庫B的用戶表里的數據IDepartment iDepartmentB = factoryB.createDepartmentConnect();iDepartmentB.insertDepartment(department);//給數據庫B的部門表增加數據iDepartmentB.selectDepartmentById(1);//查詢數據庫B的部門表里的數據}
}
在Java中還可以使用反射+配置文件進一步簡化設計,可以把工廠壓縮到只有一個,這里就不再舉例了,可以把上面的Java例子復制到你本地,運行main函數試一下加深理解。這些代碼都是我自己學習的時候根據一些教材手敲的,不存在bug可以直接運行。
如果覺得本文還不錯,就請點個贊吧!如果有建議,也請評論指教和討論!