設計模式 | 抽象工廠模式及典型應用

抽象工廠模式

抽象工廠模式(Abstract Factory Pattern):提供一個建立一系列相關或相互依賴對象的接口,而無須指定它們具體的類。抽象工廠模式又稱爲Kit模式,它是一種對象建立型模式。java

在抽象工廠模式中,每個具體工廠都提供了多個工廠方法用於產生多種不一樣類型的產品。sql

角色

在抽象工廠模式包含以下幾個角色:數據庫

  • AbstractFactory(抽象工廠):它聲明瞭一組用於建立一族產品的方法,每個方法對應一種產品。設計模式

  • ConcreteFactory(具體工廠):它實現了在抽象工廠中聲明的建立產品的方法,生成一組具體產品,這些產品構成了一個產品族,每個產品都位於某個產品等級結構中。微信

  • AbstractProduct(抽象產品):它爲每種產品聲明接口,在抽象產品中聲明瞭產品所具備的業務方法app

  • ConcreteProduct(具體產品):它定義具體工廠生產的具體產品對象,實現抽象產品接口中聲明的業務方法。ide

在抽象工廠中聲明瞭多個工廠方法,用於建立不一樣類型的產品,抽象工廠能夠是接口,也能夠是抽象類或者具體類源碼分析

具體工廠實現了抽象工廠,每個具體的工廠方法能夠返回一個特定的產品對象,而同一個具體工廠所建立的產品對象構成了一個產品族spa

抽象工廠模式總結

抽象工廠模式的主要優勢以下:操作系統

  • 抽象工廠模式隔離了具體類的生成,使得客戶並不須要知道什麼被建立。因爲這種隔離,更換一個具體工廠就變得相對容易,全部的具體工廠都實現了抽象工廠中定義的那些公共接口,所以只需改變具體工廠的實例,就能夠在某種程度上改變整個軟件系統的行爲。

  • 當一個產品族中的多個對象被設計成一塊兒工做時,它可以保證客戶端始終只使用同一個產品族中的對象。

  • 增長新的產品族很方便,無須修改已有系統,符合"開閉原則"。

抽象工廠模式的主要缺點以下:

  • 增長新的產品等級結構麻煩,須要對原有系統進行較大的修改,甚至須要修改抽象層代碼,這顯然會帶來較大的不便,違背了\"開閉原則"。

適用場景

  • 一個系統不該當依賴於產品類實例如何被建立、組合和表達的細節,這對於全部類型的工廠模式都是很重要的,用戶無須關心對象的建立過程,將對象的建立和使用解耦。

  • 系統中有多於一個的產品族,而每次只使用其中某一產品族。能夠經過配置文件等方式來使得用戶能夠動態改變產品族,也能夠很方便地增長新的產品族。

  • 屬於同一個產品族的產品將在一塊兒使用,這一約束必須在系統的設計中體現出來。同一個產品族中的產品能夠是沒有任何關係的對象,可是它們都具備一些共同的約束,如同一操做系統下的按鈕和文本框,按鈕與文本框之間沒有直接關係,但它們都是屬於某一操做系統的,此時具備一個共同的約束條件:操做系統的類型。

  • 產品等級結構穩定,設計完成以後,不會向系統中增長新的產品等級結構或者刪除已有的產品等級結構。

示例

首先定義咱們的抽象產品 ArticleVideo,他們是產品族的抽象類,有一個 Article 就有一個 Video

public abstract class Article {
    public abstract void produce();
}

public abstract class Video {
    public abstract void produce();
}

具體產品 JavaArticlePythonArticlePythonVideoJavaVideo

public class JavaArticle extends Article {
    @Override
    public void produce() {
        System.out.println("編寫Java課程筆記記");
    }
}

public class PythonArticle extends Article {
    @Override
    public void produce() {
        System.out.println("編寫Python課程筆記");
    }
}

public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("錄製Java課程視頻");
    }
}

public class PythonVideo extends Video {
    @Override
    public void produce() {
        System.out.println("錄製Python課程視頻");
    }
}

定義咱們的抽象工廠 CourseFactory,與工廠方法模式不一樣,工廠方法模式中一個工廠只生產一個產品,而抽象工廠模式中一個工廠生產一族產品,有多個工廠方法

public interface CourseFactory {
    Video getVideo();
    Article getArticle();
}

具體工廠 JavaCourseFactoryPythonCourseFactory,它們都繼承抽象工廠接口 CourseFactory

public class JavaCourseFactory implements CourseFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }

    @Override
    public Article getArticle() {
        return new JavaArticle();
    }
}

public class PythonCourseFactory implements CourseFactory {
    @Override
    public Video getVideo() {
        return new PythonVideo();
    }

    @Override
    public Article getArticle() {
        return new PythonArticle();
    }
}

客戶端只須要指定具體工廠,就能夠獲取該工廠生產的一族產品

public class Test {
    public static void main(String[] args) {
        CourseFactory courseFactory = new JavaCourseFactory();
        Video video = courseFactory.getVideo();
        Article article = courseFactory.getArticle();
        video.produce();
        article.produce();
    }
}

輸出

錄製Java課程視頻
編寫Java課程筆記

也能夠利用反射機制和配置文件,當須要修改具體工廠的時候就不須要修改客戶端代碼,只改配置文件便可

public class Test {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        // 從配置文件或數據庫等外部渠道獲取具體工廠類名
        String factoryName = "com.designpattern.JavaCourseFactory";
        // 經過反射機制獲取工廠類
        Class c = Class.forName(factoryName);
        CourseFactory courseFactory = (CourseFactory) c.newInstance();
        Video video = courseFactory.getVideo();
        Article article = courseFactory.getArticle();
        video.produce();
        article.produce();
    }
}

最終的類圖以下所示

示例.抽象工廠類圖

抽象工廠模式的典型應用及源碼分析

咱們來看 java.sql 包下的 Connection 接口,該接口定義了與特定數據庫的鏈接 Connection,執行 SQL statements 並返回 results

public interface Connection  extends WrapperAutoCloseable {
    Statement createStatement() throws SQLException;
    PreparedStatement prepareStatement(String sql) throws SQLException;
    CallableStatement prepareCall(String sql) throws SQLException;
    DatabaseMetaData getMetaData() throws SQLException;
    Savepoint setSavepoint() throws SQLException;
    Clob createClob() throws SQLException;
    Blob createBlob() throws SQLException;
    SQLXML createSQLXML() throws SQLException;
    // ...省略...
}

其中 StatementPreparedStatementCallableStatementDatabaseMetaDataSavepointClobBlobSQLXML 等均爲接口

咱們來看 Statement 接口

public interface Statement extends WrapperAutoCloseable {
    ResultSet executeQuery(String sql) throws SQLException;
    int executeUpdate(String sql) throws SQLException;
    void close() throws SQLException;
    int getMaxFieldSize() throws SQLException;
    boolean execute(String sql) throws SQLException;
    // ...省略...
}

其中的 ResultSet 又是一個接口

public interface ResultSet extends WrapperAutoCloseable {
    boolean next() throws SQLException;
    void close() throws SQLException;
    boolean wasNull() throws SQLException;
    String getString(int columnIndex) throws SQLException;
    //...省略...
}

咱們能夠看一下他們的實現類

Connection的實現類
Statement的實現類
ResultSet的實現類

能夠看出這裏邊的抽象工廠模式,Connection 爲抽象工廠,工廠方法不少,其中一個抽象產品爲 Statement,同時 Statement 也是一個抽象工廠,工廠方法也不少,其中一個抽象產品爲 ResultSet,具體工廠和具體產品則爲他們的實現類

後記

點擊[閱讀原文]可訪問個人我的博客:http://laijianfeng.org

關注【小旋鋒】微信公衆號,及時接收博文推送

參考:  
劉偉:設計模式Java版  
慕課網java設計模式精講 Debug 方式+內存分析


本文分享自微信公衆號 - 小旋鋒(whirlysBigData)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索