1. 程式人生 > >大話設計模式筆記——三種工廠模式對比

大話設計模式筆記——三種工廠模式對比

簡單工廠模式:建立一個工廠類,在類中通過具體條件選擇例項化哪個類。

工廠方法模式:定義一個用於建立物件的介面,讓子類決定例項化哪一個類。

抽象工廠模式:提供一個建立一系列相關物件的介面,而無需指定他們具體的類。

 舉個例子說明這三個模式,目前有一個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就相當於是一箇中間容器,解除了類與類之間的耦合。