1.簡單工廠模式:代替new產生對象,產品的類型比較少時。 我們要獲得三種不同的資料庫對象,如Mysql,SQLserver,Oracle,它們擁有共同的特征,即可以進行抽象,簡單工廠目的是將獲得具體資料庫實體的任務交給工廠類。 介面DataBase: 類Mysql: 類Oracle: 類SQLse ...
1.簡單工廠模式:代替new產生對象,產品的類型比較少時。
我們要獲得三種不同的資料庫對象,如Mysql,SQLserver,Oracle,它們擁有共同的特征,即可以進行抽象,簡單工廠目的是將獲得具體資料庫實體的任務交給工廠類。
介面DataBase:
public interface DataBase { public void open(); public void close(); }
類Mysql:
public class Mysql implements DataBase { @Override public void open() { System.out.println("open mysql"); } @Override public void close() { System.out.println("close mysql"); } }
類Oracle:
public class Oracle implements DataBase { @Override public void open() { System.out.println("open Oracle"); } @Override public void close() { System.out.println("close Oracle"); } }
類SQLserver:
public class SQLServer implements DataBase { @Override public void open() { System.out.println("open SQLServer"); } @Override public void close() { System.out.println("close SQLServer"); } }
工廠類及測試:
public class Factory { public DataBase getDataBase(String Type){ if(Type == null){ return null; } if(Type.equalsIgnoreCase("MYSQL")){ return new Mysql(); } else if(Type.equalsIgnoreCase("ORACLE")){ return new Oracle(); } else if(Type.equalsIgnoreCase("SQLSERVER")){ return new SQLServer(); } return null; } @Test public void test(){ Factory factory = new Factory(); DataBase d1= factory.getDataBase("MYSQL"); d1.open(); DataBase d2= factory.getDataBase("ORACLE"); d2.open(); DataBase d3= factory.getDataBase("SQLSERVER"); d3.open(); } }
特點: 如果要新增其他資料庫,只需創建新資料庫類實現功能介面,修改工廠類。
問題1:根據“開閉原則”:對現有功能進行拓展,但不允許修改原有代碼。很明顯,這時簡單工廠模式需多次修改工廠類。
問題2:使用者實際使用時並不知道類名,他只知道有DataBase這個介面,使用這個介面就能創建對象,使用open()函數,當然實際中肯定還需傳入用戶名和密碼等參數。
針對問題2:可以使用枚舉的方式,代碼如下:
public class Factory2 { enum DatabaseType{ MYSQL, SQLSERVER, ORACLE } public static DataBase getDataBase(DatabaseType type){ switch(type){ case MYSQL: return new Mysql(); case ORACLE: return new Oracle(); case SQLSERVER: return new SQLServer(); default: throw new UnknownTypeException(null, type); } } @Test public void test(){ DataBase s1=Factory2.getDataBase(DatabaseType.MYSQL); s1.open(); DataBase s2=Factory2.getDataBase(DatabaseType.ORACLE); s2.open(); } }
2.工廠方法模式(Factory Method):定義一個用於創建對象的介面,讓子類決定實例化哪一個類,使一個類的實例化延遲到其子類。
使用簡單工廠方式使得工廠函數很難維護,而且請求者還需知道被實例化的類,而工廠方法模式可避免之。
新建抽象工廠 IFactory,對於每個資料庫都新建相應的工廠類,如MysqlFactory,OracleFactory實現 IFactory,這樣在新增一種資料庫時,不必修改工廠類而造成破壞封閉原則。
public interface IFactory { public DataBase get(); }
class SqlFactory implements IFactory{ public DataBase get(){ return new Mysql(); } } class OracleFactory implements IFactory{ public DataBase get(){ return new Oracle(); } } class SQLserverFactory implements IFactory{ public DataBase get(){ return new SQLServer(); } } //測試 public class FactoryMethod{ public static void main(String[] args){ DataBase d1=new SqlFactory().get(); d1.open(); } }
問題1:如果資料庫類型越來越多,將無限的增加工廠子類,使用者同樣還是需要知道工廠子類的名稱。
問題2:在使用時資料庫時可能還需與其他的類相關聯,工廠方法模式無法解決。
3.抽象工廠模式(Abstract Factory):提供一個創建一系列相關或者相互依賴對象的介面,而無需指定它們具體的類。
場景:若在新建資料庫連接時需指定方言,而且不同資料庫的SQL語言也不相同的情況下。
組成元素:
1.方言類和介面,如圖所示:
2.之前的資料庫類和介面
3.operFactory抽象工廠
public abstract class operFactory{ private IDialect dialect; abstract void add(); abstract void delete(); abstract void update(); public void setDialect(String classname){ IDialect cf=null; try { cf=(IDialect)Class.forName(classname).newInstance(); setDialect(cf); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } } public IDialect getDialect() { return dialect; } public void setDialect(IDialect dialect) { this.dialect = dialect; } }
4. MysqlFatory,OracleFactory( 均繼承上面的抽象工廠類)
public class MysqlFatory extends operFactory { @Override void add() { System.out.println("使用的方言為:"+this.getDialect().showDialect()); System.out.println("mysql add()"); } @Override void delete() { System.out.println("使用的方言為:"+this.getDialect().showDialect()); System.out.println("mysql delete()"); } @Override void update() { System.out.println("使用的方言為:"+this.getDialect().showDialect()); System.out.println("mysql update()"); } } public class OracleFactory extends operFactory { @Override void add() { System.out.println("使用的方言為:"+this.getDialect().showDialect()); System.out.println("Oracle add()"); } @Override void delete() { System.out.println("使用的方言為:"+this.getDialect().showDialect()); System.out.println("Oracle delete()"); } @Override void update() { System.out.println("使用的方言為:"+this.getDialect().showDialect()); System.out.println("Oracle update()"); } }
5.工廠構造器類 FactoryProducer 負責生成想要的資料庫工廠。
public class FactoryProducer { public static operFactory getFactory(String class_name) { operFactory cf=null; try { cf=(operFactory)Class.forName(class_name).newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } return cf; } }
6.測試
public static void main(String[] args){ operFactory of2=FactoryProducer.getFactory(DatabaseFactoryType.MYSQL); of2.setDialect(DialectType.MySQL5InnoDBDialect); of2.update(); operFactory of= FactoryProducer.getFactory(DatabaseFactoryType.ORALCE); of.setDialect(DialectType.Oracle10gDialect); of.add(); }
結果:
總之抽象工廠總是關於創建一系列相關或相互有依賴的對象,以上例子中即DataBase對象與Dialect對象具有相關性。但是使用者要瞭解各種工廠和方言。
三者區別:
簡單工廠實現簡單,擴展也很容易,但是會頻繁修改工廠類代碼,難以維護,在維護的時候容易引發新的BUG。
工廠方法模式則是把對象的實例化延遲到了繼承的子類裡面,這樣就變成了擴展工廠,從而滿足了“開閉”原則, 但是不支持產品切換,也就是只能滿足一層的產品(演算法)抽象,當需與其他對象合作時無能為力。
抽象工廠則是繼續把產品進行再次抽象,最後得到一個可以支持產品切換的結構,但問題過於複雜,不過我們使用反射機制,可以彌補這個缺點,但是使用者卻需要知道工廠的名稱。
以上工程源碼分享:鏈接:https://pan.baidu.com/s/1ElHalIZKrr1n7391jW8uTA 密碼:1ikz