設計模式-三種工廠模式實例


  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

          

 

  

 

      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM