淺談 簡單工廠模式,工廠方法模式,抽象工廠模式的優點和缺點
阿新 • • 發佈:2019-02-12
1.簡單工廠模式:
簡單工廠模式的實質是由一個工廠類根據傳入的引數 動態決定應該創建出哪一個產品類的例項
工廠類角色,抽象產品角色,具體產品角色
嚴格說這並不是一個設計模式,簡單工廠沒有抽象類,只有一個工廠類,這個類有個工廠方法是專門返回一個具體產品類,具體返回什麼具體例項是根據傳入的引數要CASE判斷的
用手機生產做例子:
比如說諾基亞簡單工廠用於生產手機的,傳入的引數是手機型號,根據不同的型號生少不同的手機,很明顯缺點就是每生產一個新型號手機就要修改工廠類,增加CASE判斷,這就違背了開放-封閉原則
程式碼如下:
// 簡單工廠類
public class SimpleFactory {
private Work work;
public Object workObject(int i) {
switch (i) {
case 1:
work = new StudentWorkImp();
break;
case 2:
work = new TeacherWorkImpl();
break;
default:
break;
}
return work;
}
}
//抽象產品介面
public interface Work {
public void doWork();
}
//具體產品類
public class StudentWorkImp implements Work {
public void doWork() {
System.out.println("學生做作業");
}
}
public class TeacherWorkImpl implements Work {
public void doWork() {
System.out.println("老師改作業");
}
}
2.工廠方法模式
定義一個用於建立物件的介面 讓子類來決定建立哪一個具體類
參與角色:
抽象產品角色 具體產品角色 抽象工廠角色 具體產品工廠角色
該模式繼承了簡單工廠模式的優點又克服了它的缺點 但它本身也有缺點 就是每增加一個產品類的時候都需要增加一個具體產品工廠類 增加了額外的開發量
用生產手機例子:
該模式有一個生產諾基亞的抽象類,該類裡有個方法是專門生產抽象產品類的,然後不同型號的手機對應一個該型號的手機工廠,比如N97factory,此類繼承抽象工廠類,類方法是專門生產具體產品類的
程式碼如下:
//抽象產品角色
public abstract class IWork {
public void doWork(){
}
}
//具體產品角色
public class StudentWork extends IWork{
public void doWork(){
System.out.println("學生做作業");
}
}
//具體產品角色
public class TeacherWork extends IWork{
public void doWork(){
System.out.println("老師做作業");
}
}
//抽象產品工廠
public abstract class ClassFactory {
public IWork getWork(){
return null;
}
}
//具體產品工廠
public class StudentClassFactory extends ClassFactory{
public IWork getWork(){
return new StudentWork();
}
}
//具體產品工廠
public class TeacherClassFactory extends ClassFactory{
public IWork getWork() {
return new TeacherWork();
}
}
3.抽象工廠模式
該模式和與工廠方法模式很相似,也是有個參與角色,抽象產品角色,具體產品角色,抽象工廠角色,具體工廠角色,不同的是抽象工廠類裡面有多個虛工廠方法
它在我們系統實際設計當中考慮的是資料庫的遷移,到時候再更改資料訪問層會很麻煩,因為每種資料庫的語法是不一樣的,我們不能保證在以後肯定不會這麼做,所以要在起初設計的時候就要考慮到這點,
現在我們模仿DAO層訪問資料:
//pojo
public class User{
private String name;
private int age;
//get() set()....
}
public interface UserDao(){
public void addUser(){}
public void updateUser(){}
}
public class UserDaoMS() implements UserDao{
public void addUser(){
//mysql 的語法
}
public void updateUser(){
//mysql 的語法
}
}
現在如果我們要把mysql遷移到orcale 為了不改動原有的程式碼要依據開放封裝的原則勢必會這麼做
//pojo
public class User{
private String name;
private int age;
//get() set()....
}
public interface UserDao(){
public void addUser(){}
public void updateUser(){}
}
//mysql實現
public class UserDaoMS() implements UserDao{
public void addUser(){
//mysql 的語法
}
public void updateUser(){
//mysql 的語法
}
}
// orcle實現
public class UserDaoOR() implements UserDao{
public void addUser(){
//orcle 的語法
}
public void updateUser(){
//orcle 的語法
}
}
如果這樣做的話,當在Service層呼叫DAO層的時候需要改動的地方依然很多,這樣也不是很好的設計,現在我們用了工廠方法模式實現一下
//首先一個抽象工廠介面
public interface AccessFactory{
public UserDao createUserDao();
}
public class DAOFactoryMS implements AccessFactory{
public UserDao createUseDao(){
return new UserDaoMS();
}
}
public class DAOFactoryOR implements AccessFactory{
public UserDao createUseDao(){
return new UserDaoOR();
}
}
如果按照這樣的設計在Service層呼叫DAO的時候只要呼叫 AccessFactory。createUserDao()就可以得到一個具體例項以訪問資料了
這樣設計也有一個弊端,如果這時只有一個User實體是可以這樣做的,因為工廠方法模式的抽象工廠角色中只有一個虛方法是可以返回一個抽象產品例項的
如果還有別的實體如 部門,職位這個實體,所要改動的依然很多,如果我們運用了抽象工廠模式也可以解決了這個問題,但是這樣設計就會太繁瑣,為什麼這麼說呢
請看下圖
之前中有一個User實體,從而對這上實本的增刪改查操作,現在多了部門實體,我們就要每增加一個實體就要多加三個類 還要更改一個抽象工廠類,兩個具體工廠類
另外有很多地方都要呼叫 User 和部門的DAO 當在service層裡的具體類裡呼叫他們的時候都需要宣告 AccessFactory factory = new MSfactory();如果有100個就會更改100次,
這樣的效率是極低的,所以有一個辦法可以解決所有問題那就是 兩個模式的合併:簡單工廠和抽象工廠
程式碼如下:
public class DataAccess{
private String db = "MS"; //代表是MYSQL
public static UserDao createUserDao(){
Class<?> classType = Class.forName("UserDao"+db);
Object object = classType.newInstance();
return (UserDao)new object();
}
}
這個原理用的JAVA的反射機制,這兩個模式的合併很好解決了以上出現的問題符合了開放-封閉原則。
總結:用最簡單的話來概括就是,簡單工廠只有一個具體工廠類來建立一種基類的多個不同派生類,工廠方法就是有多個派生於一個基類的具體工廠類,每個具體工廠只生產一種基類的一個派生類,抽象工廠也是隻有一個工廠基類,但是每個具體工廠生產多個相關基類的各一個派生類。