1. 程式人生 > >設計模式系列之三:抽象工廠模式

設計模式系列之三:抽象工廠模式

前言

在設計模式有三個模式是與工廠模式相關的,分別是:簡單工廠模式、工廠方法模式以及抽象工廠模式。在前面的文章中已經談到前面兩種,這裡就對抽象工廠模式介紹一下。抽象工廠模式就是提供一個建立一系列相關或者相互依賴的介面(也就是抽象類),而無需指定具體的類。簡單來說,就是當我們需要建立一個具體的物件的時候,我們不必指定該具體的物件,只需要使用它的上層介面直接呼叫就行。好像還是很抽象哦,好吧,為了更清晰領悟這個設計模式,我們還是通過一個案例來說明

問題背景

某公司開發了一個A軟體,資料庫使用的是SQLServer。後由於客戶要求需要使用Oracle資料庫,原來的資料要遷移到Oracle中,在遷移的過程中遇到很多問題,比如語法錯誤,關鍵字濫用,函式不支援等問題。請設計一組程式,實現資料的無縫遷移。

簡介

通過使用我們的工廠方法模式,我們已經較好的解決了使用者使用不同資料庫的問題,現在我們已經獲得了要建立的資料庫物件,那麼接下來我們就需要向資料庫中新增資料了,假設都需要新增部門資訊,有的使用者需要使用Oracle,有的使用者需要使用SqlServer。考慮抽象工廠模式的程式碼結構:

抽象工廠模式結構圖

抽象工廠模式實現

在修改程式碼結構之前,為了更好的對比,來看一下我們現在的程式碼結構:

初始類圖

修改之前(基於抽象工廠模式)

原始程式碼v1.0:

    public interface IFactory {
    //建立資料庫物件
    DBObject createDBObject();
    //建立部門
IDepartment createDepartment(); } public class OracleFactory implements IFactory{ @Override public DBObject createDBObject() { return new OracleObject(); } @Override public IDepartment createDepartment() { return new OracleDepartment(); } } public
class SqlServerFactory implements IFactory{ @Override public DBObject createDBObject() { return new SqlServerObejct(); } @Override public IDepartment createDepartment() { return new SqlServerDepartment(); } } public abstract class DBObject { //新增使用者的方法 public abstract void insertUser(User user); //查詢使用者資訊的方法 public abstract User findUserById(int id); } public class OracleObject extends DBObject{ @Override public void insertUser(User user) { System.out.println("使用Oracle新增使用者"); } @Override public User findUserById(int id) { System.out.println("使用Oracle通過id找到使用者"); return null; } } public class SqlServerObejct extends DBObject{ @Override public void insertUser(User user) { System.out.println("使用SQLServer新增使用者"); } @Override public User findUserById(int id) { System.out.println("使用SQLServer通過id找到使用者"); return null; } } public interface IDepartment { //建立部門 void insertDept(Department dept); //查詢部門 Department findDeptById(int id); } public class OracleDepartment implements IDepartment { @Override public void insertDept(Department dept) { System.out.println("使用Oracle物件插入一條部門資訊"); } @Override public Department findDeptById(int id) { System.out.println("使用Oracle物件查詢id為" + id + "的部門資訊"); return null; } } public class SqlServerDepartment implements IDepartment { @Override public void insertDept(Department dept) { System.out.println("使用SqlServer物件新增一條部門資訊"); } @Override public Department findDeptById(int id) { System.out.println("使用SqlServer物件查詢id為" + id + "的部門資訊"); return null; } } //測試方法 public static void main(String[] args){ IFactory factory = new OracleFactory(); IFactory factory2 = new SqlServerFactory(); IDepartment department = factory.createDepartment(); IDepartment department2 = factory2.createDepartment(); department.insertDept(dept); department.findDeptById(1); department2.insertDept(dept); department2.findDeptById(2); }

第一次修改(基於簡單工廠模式)

根據抽象工廠模式結構圖以及需求,修改程式碼如下:
1) 增加一個建立部門的抽象工廠,這裡使用介面
2) 分別建立基於Oracle以及基於SqlServer的部門實現類(已經在上面的程式碼中實現)
3) 建立一個數據庫工具類,根據條件建立需要的物件
修改的程式碼v1.1

    public class DBAccess {
    //這裡固定DBTYPE的值,如果要使用其他資料庫,修改這個欄位的值就好
    private static final String DBTYPE = "oracle";
    public static DBObject createDBObject(){
        switch (DBTYPE){
            case "oracle":
                return new OracleObject();
            case "sqlserver":
                return new SqlServerObejct();
        }
        return null;
    }

    public static IDepartment createDepartment(){
        switch (DBTYPE) {
        case "oracle":
            return new OracleDepartment();
        case "sqlserver":
            return new SqlServerDepartment();
        }
        return null;
    }
    }
    //測試方法
    public static void main (String[] args){
        User user = new User();
        Department dept = new Department();

        //這裡創建出來的DBObject就是上面DBTYPE指定值的資料庫物件
        DBObject dbObject = DBAccess.createDBObject();
        dbObject.insertUser(user);
        dbObject.findUserById(1);

        IDepartment department = DBAccess.createDepartment();
        department.insertDept(dept);
        department.findDeptById(1);
    }

這裡通過DBAccess類直接替代了原來的IFactory、OracleFactory、SqlServerFactory三個類,這裡實際上是簡單工廠的實現方法,把判斷邏輯轉移到DBAccess中,客戶端不需要做任何修改,要更換資料庫只需要在DBAccess中把DBTYPE的值修改就ok。在這點上,好像簡單工廠佔優勢,但是不盡然,如果要在程式中新增對MySQL資料庫的支援,如果使用原來抽象工廠模式。只需要新增一個MySQLFactory類就行,現在就需要在DBAccess類中修改邏輯判斷了(在這一點違背了封閉開放原則)。那麼有沒有一種方法,不要增加對switch的判斷就可以根據DBTYPE的值建立相應的物件呢?也就是說,在程式執行期間,根據類的字串表示建立類的例項。答案是肯定的,在Java中我們可以利用反射技術做到這一點,所以我們對v1.1版的程式碼進行進一步的修改:

第二次修改(基於反射技術)

v1.2

    public class DBAccess {
        private static final String DBTYPE = "Oracle";
        public static DBObject createDBObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
            return (DBObject) Class.forName("com.rhwayfun.GoF." + DBTYPE + "Object").newInstance();
        }

        public static IDepartment createDepartment() throws InstantiationException, IllegalAccessException, ClassNotFoundException{
            return (IDepartment) Class.forName("com.rhwayfun.GoF." + DBTYPE + "Department").newInstance();
        }
    }

現在,如果需要增加對MySQL的支援只需要修改Oracle為MySQL就行,不過還是得建立MySQLObject類以及MySQLDepartment類,但是與上面簡單工廠模式的修改不同,這裡只是在原來程式碼的基礎增加,是擴充套件而不是修改。所以沒有違背開放-封閉原則,現在這版的程式碼比之前好多了,但是DBTYPE的值仍然不可避免要進行修改,事實上還有一種通過配置檔案的方式可以儲存原來的程式碼不變而實現這個功能,下面對程式碼進行第三次修改:

第三次修改(基於配置檔案+反射技術)

首先建立db.properties配置檔案

    DBTYPE=Oracle

v1.3版程式碼

public class DBAccess {
        public static DBObject createDBObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException{
            return (DBObject) Class.forName("com.rhwayfun.GoF." + readPro() + "Object").newInstance();
        }

        public static IDepartment createDepartment() throws InstantiationException, IllegalAccessException, ClassNotFoundException, IOException{
            return (IDepartment) Class.forName("com.rhwayfun.GoF." + readPro() + "Department").newInstance();
        }

        private static String readPro() throws IOException{
            Properties pro = new Properties();
            InputStream in = DBAccess.class.getClassLoader().getResourceAsStream("com/rhwayfun/GoF/db.properties");
            pro.load(in);
            return (String) pro.get("DBTYPE");
        }
    }

客戶端程式碼保持不變,實際測試成功。

抽象工廠模式小結

從v1.0到v1.3我們對工廠模式做一個簡單的小結:

  • 所有使用簡單工廠的都可以考慮使用反射技術加以優化
  • 抽象工廠的最大好處是便於交換產品系列,要建立不同的產品,我們可以使用不同的工廠建立。所以當我們需要不同產品線的產品的時候只需要換一個工廠就可以輕鬆實現
  • 抽象工廠模式與工廠方法模式把建立例項的過程與客戶端分離,使用者操作的只是抽象介面,而具體的建立過程則封裝到了具體的工廠去實現。很好的體現了開放-封閉的原則
  • 抽象工廠模式與抽象工廠模式都存在一個缺點,就是需要增加新功能的時候,要建立的類很多。
  • 簡單工廠模式可以通過反射技術克服上訴缺點,但使用反射會降低程式的效能,所以雖然使用反避免了建立多個類的麻煩,卻也同時降低了程式的效能,所謂有得必有失。在實際的開發中還是需要仔細衡量的。

相關推薦

設計模式系列抽象工廠模式

前言 在設計模式有三個模式是與工廠模式相關的,分別是:簡單工廠模式、工廠方法模式以及抽象工廠模式。在前面的文章中已經談到前面兩種,這裡就對抽象工廠模式介紹一下。抽象工廠模式就是提供一個建立一系列相關或者相互依賴的介面(也就是抽象類),而無需指定具體的類。簡單來

設計模式抽象工廠模式

     抽象工廠模式(Abstract Factory Pattern):      定義:Provide an interface for creating families of related or dependent objects without specify

設計模式系列工廠模式(Factory Pattern)

這是本系列的第三篇部落格,這次主要來說一下工廠模式。 基本工廠模式 簡單來說工廠模式是將工程中的相同型別物件的建立活動集中管理,一般通過反射來生成外界需要的實體類。比如Spring中的容器Bean概念,通過Spring BeanFactory來產生不同的Be

Java設計模式工廠模式(二)抽象工廠模式

mar 模式 blank http left taxi ref www. app 2碳依5FVL冒傲3http://t.docin.com/etw488 am懦7鈉N山段9慌Q闌http://shequ.docin.com/ipu5657 iK1諾5N鍛認EUK剖嘲肆h

經典設計模式()抽象工廠模式

抽象工廠模式 本來不想寫這篇文章的,應該是不想寫工廠模式,因為基本大家都會,不過今天看到一個老鐵的部落格,https://www.yuxuan66.com/16 關於抽象模式的實現,寫得不錯,看了幾遍之後,有了點自己的想法,隨便再熟悉一下工廠模式,於是就有了這篇文章,主要是抽象工廠

Java設計模式抽象工廠模式

一、什麼是抽象工廠模式 抽象工廠模式是所有形態的工廠模式中最為抽象和最其一般性的。抽象工廠模式可以向客戶端提供一個介面,使得客戶端在不必指定產品的具體型別的情況下,能夠建立多個產品族的產品物件。 二、產品族和產品等級結構 三、模式中包含的角色及其職責 1.抽象工廠(C

設計模式抽象工廠模式

抽象工廠模式(Abstract Factory Pattern)是圍繞一個超級工廠建立其他工廠。該超級工廠又稱為其他工廠的工廠。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。 在抽象工廠模式中,介面是負責建立一個相關物件的工廠,不需要顯式指定它們的類。每

23種設計模式(3)抽象工廠模式

如果 劃分 產品 升級版本 特點 client 形式 inter system 定義:為創建一組相關或相互依賴的對象提供一個接口,而且無需指定他們的具體類。 類型:創建類模式。 類圖: 抽象工廠模式與工廠方法模式的區別 抽象工廠模式是工廠方法模式的升級版本,他用來創

設計模式(2)抽象工廠模式

在抽象工廠模式中,介面負責建立相關物件的工廠,而不明確指定它們的類。 每個生成的工廠可以按照工廠模式提供物件。 1.建立Shape的介面 public interface Shape { void draw(); } 2.建立實現相同介面的具體類 public

JAVA設計模式(2)抽象工廠模式

抽象工廠模式是一個超級工廠,用來建立其他工廠。 這個工廠也被稱為工廠的工廠。 這種型別的設計模式屬於建立模式,因為此模式提供了建立物件的最佳方法之一。在抽象工廠模式中,介面負責建立相關物件的工廠,而不明確指定它們的類。 每個生成的工廠可以按照工廠模式提供物件。 實現例項 我們將建立一個Sha

設計模式系列(11)抽象工廠模式

1.概念   抽象工廠模式是所有形態的工廠模式中最為抽象最為一般性的。抽象工廠模式可以向客戶端提供一個介面,使得客戶端在不必指定產品具體型別的情況下,能夠建立多個產品族的產品物件。 備註:工廠模式要麼

設計模式系列建造者模式

1.定義 將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示 2.通用類圖 Product 產品類:表示被構造的複雜物件。通常實現了模板方法模式,也就是有基本方法和模板方法 Builder 抽象建造者:規範產品的元件,一

CNCF CNI系列flannel vxlan模式工作原理淺析

一、前言flannel為container提供網路解決方案。flannel有一個基於etcd cluster的資料交換中心,每個節點上有flannel service,每個節點被分配不同的網段,每個節點上的container從該網段獲取IP。一個節點之間通過一個overlay

C#設計模式創建類模式抽象工廠模式

nfa display color 職責 product 依賴對象 pset 並不是 config 定義:提供一個創建一系列相關或相互依賴對象的接口,而無須指定他們具體的類。 概念 要理解抽象工廠模式,首先要了解幾個概念,一個是產品等級結構,另一個是產品族。 在工廠方法模

Java設計模式(二)建立型模式抽象工廠模式

例子背景: 隨著客戶的要求越來越高,寶馬車需要不同配置的空調和發動機等配件。於是這個工廠開始生產空調和發動機,用來組裝汽車。這時候工廠有兩個系列的產品:空調和發動機。寶馬320系列配置A型號空調和A型號發動機,寶馬230系列配置B型號空調和B型號發動機。   一、概念:

Java 設計模式抽象工廠模式

參考連結:抽象工廠模式-Abstract Factory Pattern 工廠方法模式解決了簡單工廠模式存在的問題,但由於工廠方法模式中的每個工廠只生產一類產品,可能會導致系統中存在大量的工廠類,勢必會增加系統的開銷。此時,我們可以考慮將一些相關的產品組成一個“產品族”,由同一個工廠

設計模式)---抽象工廠模式

ava des 模式 println 5.5 mage test 抽象工廠 urn 1、 簡介:為創建一組相關或相互依賴的對象提供一個接口,無需指定它們的具體類。抽象工廠模式通常是用於創創建一族產品,並且這族產品分不同的等級;不同的具體工廠類生產不同等級的一族產品。 2、

磊哥學設計模式抽象工廠模式

抽象工廠 什麼是抽象工廠 抽象工廠模式(Abstract Factory Pattern)是圍繞一個超級工廠建立其他工廠。該超級工廠又稱為其他工廠的工廠。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。 在抽象工廠模式中,介面是負責建立一個相關物件的工廠,不需要

設計模式單例模式(餓漢式與懶漢式)

//保證類在記憶體中只有一個物件 package com.xjh.demo.designpattern.pattern3; public class Student { private Student(){ } //懶漢式 priva

C++重寫《大話設計模式》中模式例項抽象工廠模式

(宣告:如果想看例項詳細解析,請看《大話設計模式》,這裡文章只是為了加深學習設計模式印象而自己用C++程式寫一遍,以及把程式碼共享給大家。僅僅是把C#語言換成C++表述,不對書中的程式和例子是否合適做個