這裏又出現了一個抽象工廠模式,這個抽象工廠模式又是什麼呢?sql
咱們如今來模擬一個場景,如今用的是Mysql數據庫,明天讓你更換爲Oracle數據庫。此時,想一想要作多少的改動。但咱們若是用工廠模式,這會讓你節省大量時間。數據庫
首先,咱們用工廠方法模式來設計這個程序。框架
咱們畫出類的UML圖。ide
IFactory做爲工廠類的接口,有兩個子類,分別用來構造不一樣的實例。spa
IFactory工廠接口代碼以下:設計
package day_3_facoryMethod_db; /** * 數據庫工廠類 * @author turbo * * 2016年9月6日 */ public interface IFactory { IUser createUser(); }
MysqlFactory代碼以下,省去OracleFactory。code
package day_3_facoryMethod_db; /** * @author turbo * * 2016年9月6日 */ public class MysqlFactory implements IFactory { /* (non-Javadoc) * @see day_3_facoryMethod_db.IFactory#createUser() */ @Override public IUser createUser() { return new MysqlUser(); } }
IUser是對User表操做的接口,不一樣數據庫的操做只需繼承實現它便可。對象
package day_3_facoryMethod_db; /** * 操做數據庫User表的接口 * @author turbo * * 2016年9月6日 */ public interface IUser { void insert(User user); User getUserById(int userId); }
MysqlUser是對IUser接口的實現,是對User表操做的具體實現。省去OracleUser。blog
package day_3_facoryMethod_db; /** * Mysql對User表的操做 * @author turbo * * 2016年9月6日 */ public class MysqlUser implements IUser { /* (non-Javadoc) * @see day_3_facoryMethod_db.IUser#insert(day_3_facoryMethod_db.User) */ @Override public void insert(User user) { System.out.println("插入一條數據"); } /* (non-Javadoc) * @see day_3_facoryMethod_db.IUser#getUserById(int) */ @Override public User getUserById(int userId) { System.out.println("獲取一條數據"); return null; } }
如今經過客戶端代碼來觀察是如何作到業務邏輯和數據訪問的解耦的。繼承
package day_3_facoryMethod_db; /** * 客戶端 * @author turbo * * 2016年9月6日 */ public class Main { public static void main(String[] args){ IFactory factory = new MysqlFactory(); //若是須要修改數據庫,則只需將new MysqlFactory()修改成new OracleFactory()。 IUser iu = factory.createUser(); iu.insert(new User()); iu.getUserById(1); } }
若是要更改數據庫,則只需將new MysqlFactory()修改成new OracleFactory()便可,這就是所謂的業務邏輯和數據訪問的解耦。
上面咱們實際上從新回顧了工廠方法模式,彷佛已經達到了咱們想要的效果。可是,數據庫裏不止一張表,兩個數據庫又是兩大不一樣分類,解決這種涉及多個產品系列的問題,有一個專門的工廠模式叫抽象工廠模式。因此實際上,若是增長一個新表,上面的工廠方法模式就有了一個新的名字——抽象工廠模式。
抽象工廠模式:提供一個建立一些列有關或互相依賴對象的接口,而無需制定它們具體的類。
下面咱們進階一下:用反射+抽象工廠的方式來設計這個程序。
是否記得在簡單工廠模式中,咱們用到了switch或者if。有用到switch和if的地方,咱們均可以考慮利用反射技術來去除,以解除分支帶來的耦合。
這其實將會引伸一個概念:依賴注入(DI),或者稱爲控制反轉,將傳統上由程序代碼直接操控的對象的調用權交給容器,經過容器來實現對象組件的裝配和管理,什麼意思?就是直觀上代碼裏看不到new 對象,這個操做交給了外部容器,這樣將會大大下降程序的耦合性。好比:Spring框架的IoC容器。
咱們先來看若是要實例化上面的的IUser會怎麼作?
IUser iu = new MysqlUser();
若是是用反射呢?
Class classType = Class.forName("day_3_facoryMethod_db.MysqlUser"); //「類所在的包名.類名」
Object obj = classType.newInstance();
咱們對obj作驗證。
System.out.println(obj instanceof MysqlUser);
輸出爲true,用反射機制成功實例化對象。
反射和直接new有什麼區別呢?答案就在於:反射使用的字符串,也就是說能夠用變量來處理。而new的常規方法是已經編譯好了的,不能隨意靈活更換其實例化對象。因此,思考,若是咱們用配置文件的方式,是否是能靈活替換咱們想要的實例化對象呢?