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

来源:https://www.cnblogs.com/erroranswer/archive/2018/08/24/9529364.html
-Advertisement-
Play Games

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

          

 

  

 

      


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 此文是我的出版書籍[《React Native 精解與實戰》](http://rn.parryqiu.com/)連載分享,此書由機械工業出版社出版,書中詳解了 React Native 框架底層原理、React Native 組件佈局、組件與 API 的介紹與代碼實戰,以及 React Native... ...
  • 【要點】 1. HTTP協議的主要特點 2. HTTP報文的組成部分 3. HTTP方法 4. POST 和 GET的區別 5. HTTP狀態碼 【總結】 HTTP協議的主要特點 主要特點:簡單快速, 靈活, 無連接(非keep-alive),無狀態 每個資源URI是固定的,想訪問某個資源 ,瀏覽器 ...
  • 深度優先遍歷:對每一個可能的分支路徑深入到不能再深入為止,而且每個結點只能訪問一次。要特別註意的是,二叉樹的深度優先遍歷比較特殊,可以細分為先序遍歷、中序遍歷、後序遍歷。 二叉樹最大深度: 如果二叉樹為空,則深度為0 如果不為空,分別求左子樹的深度和右子樹的深度,取最大的再加1。 ...
  • 為什麼監控 用(上)戶(帝)說,這個頁面怎麼這麼慢,還有沒有人管了?! 簡單而言,有三點原因: 關註性能是工程師的本性 + 本分; 頁面性能對用戶體驗而言十分關鍵。每次重構對頁面性能的提升,僅靠工程師開發設備的測試數據是沒有說服力的,需要有大量的真實數據用於驗證; 資源掛了、載入出現異常,不能總靠用 ...
  • 表格展示神器之一:layui表格 前言:在寫後臺管理系統中使用最多的就是表格數據展示了,使用表格組件能提高大量的開發效率,目前主流的數據表格組件有bootstrap table、layui table、easyUI table等.... 博主個人比較傾向於layui,layui極簡,卻又不失飽滿的內 ...
  • 添加padding-right:1em; ...
  • jQuery.parents("選擇器") ...
  • <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>JS2</title> <style type="text/css"> #d1{ height: 100px; width: 100px; background-color: red; ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...