大話設計模式筆記——三種工廠模式對比
簡單工廠模式:建立一個工廠類,在類中通過具體條件選擇例項化哪個類。
工廠方法模式:定義一個用於建立物件的介面,讓子類決定例項化哪一個類。
抽象工廠模式:提供一個建立一系列相關物件的介面,而無需指定他們具體的類。
舉個例子說明這三個模式,目前有一個User類,它有兩個方法,是用MySQL語法實現的。
public class User{ private int id; private String name; //get和set方法省略 } public class MysqlUser{ public void insertUser(User user){ //插入方法 } public User selectUser(int id){ //查詢方法 } } 客戶端呼叫 public static void main(String[] args){ User user = new User(); MysqlUser mysqlUser = new MysqlUser(); mysqlUser.insertUser(user); mysqlUser.selectUser(1); }
如果現在要把資料庫改成sqlServer該怎麼辦,需要修改大量客戶端程式碼,程式碼對具體資料庫的依賴程度太高,導致耦合性高。
現在用工廠模式實現,定義一個介面,讓子類決定例項化哪個類,讓業務邏輯與資料訪問解耦。
public interface IUser{ void insertUser(User user); User selectUser(int id); } public class MysqlUser implements IUser{ public void insertUser(User user){ //MysqlUser插入方法 } public User selectUser(int id){ //MysqlUser查詢方法 } } public class SqlserverUser implements IUser{ public void insertUser(User user){ //SqlserverUser插入方法 } public User selectUser(int id){ //SqlserverUser查詢方法 } } 工廠類 public interface IFactory{ IUser createUser(); } public class MysqlFactory implements IFactory{ public IUser createUser(){ return new MysqlUser(); } } public class SqlserverFactory implements IFactory{ public IUser createUser(){ return new SqlserverUser(); } } 客戶端 public static void main(String[] args){ User user = new User(); IFactory factory = new MysqlFactory(); IUser iu = factory.createUser(); iu.insertUser(); iu.selectUser(); }
當切換資料庫時只需修改工廠類的具體例項化即可,也就是new MysqlFactory()改為new SqlserverFactory()。如果在加上一個部門類及其方法該怎麼辦呢?僅僅只需要在IFactory中新增一個createDepartment()方法,再在具體的工廠實現類中加入建立部門的具體實現方法,並不影響客戶端程式碼。這就變成了抽象工廠模式。
抽象工廠模式便於不同型別產品之間的切換,並且具體建立例項的過程與客戶端分離,客戶端通過抽象介面操縱例項,產品的具體類名也被具體的工廠實現分離,不會出現在客戶端程式碼中。但是每次進行資料庫的訪問,都要加上一個IFactory factory = new MysqlFactory();下面用簡單工廠模式來實現。
public class DbFactory{
private static db = "mysql";
//private static db = "sqlserver";
public static IUser createUser(){
IUser result = null;
switch(db){
case "mysql":
result = new mysqlUser();
case "sqlserver":
result = new sqlserverUser();
}
return result;
}
}
客戶端
public static void main(String[] args){
User user = new User();
IUser iu = DbFactory.createUser();
iu.insertUser(user);
iu.selectUser(1);
}
客戶端中並沒有出現具體資料庫的名稱,實現瞭解耦。只需在資料庫工廠中進行切換db的值,但是如果現在在加上一個oracle資料庫,DbFactory中每個方法的switch中都得加個case語句。下面用反射來實現
public class DbFactory{
private static db = "mysql";
//private static db = "sqlserver";
public static IUser createUser(){
String className = db + "User";
return (IUser)class.forName(className).newInstance();
}
}
客戶端程式碼同上
到這個程度,已經非常簡單了,切換資料庫只需要修改db就可以了,但還是得修改程式,我們可以增加一個xml檔案,將資料庫的資訊配置在xml中,在DbFactory中讀取檔案資訊即可,這樣每次只需要修改配置檔案就可以了,不用修改程式,實現了完全的解耦。
這種通過反射的方式找到需要例項化類的方法就叫依賴注入,突然之間感覺對spring的理解又加深了,spring提供了一個專門的IOC容器,通過配置檔案或者註解的方式將類注入進去,當其他的類需要呼叫注入到spring中的類時,只需要加上@Autowired這個註解,spring就相當於是一箇中間容器,解除了類與類之間的耦合。