• <menu id="gyiem"><menu id="gyiem"></menu></menu>
  • <menu id="gyiem"><code id="gyiem"></code></menu>

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

    原創文章,轉載請務必將下面這段話置于文章開頭處(保留超鏈接)。
    本文轉發自技術世界原文鏈接 http://www.luozeyang.com/design_pattern/abstract_factory/

    抽象工廠模式解決的問題

    上文《工廠方法模式》中提到,在工廠方法模式中一種工廠只能創建一種具體產品。而在抽象工廠模式中一種具體工廠可以創建多個種類的具體產品。

    抽象工廠模式

    抽象工廠模式介紹

    抽象工廠模式(Factory Method Pattern)中,抽象工廠提供一系列創建多個抽象產品的接口,而具體的工廠負責實現具體的產品實例。抽象工廠模式與工廠方法模式最大的區別在于抽象工廠中每個工廠可以創建多個種類的產品。

    抽象工廠模式類圖

    抽象工廠模式類圖如下 (點擊可查看大圖)
    Factory Method Pattern Class Diagram

    抽象工廠模式角色劃分

    • 抽象產品(或者產品接口),如上文類圖中的IUserDao,IRoleDao,IProductDao
    • 具體產品,如PostgreSQLProductDao
    • 抽象工廠(或者工廠接口),如IFactory
    • 具體工廠,如果MySQLFactory
    • 產品族,如Oracle產品族,包含OracleUserDao,OracleRoleDao,OracleProductDao

    抽象工廠模式使用方式

    與工廠方法模式類似,在創建具體產品時,客戶端通過實例化具體的工廠類,并調用其創建目標產品的方法創建具體產品類的實例。根據依賴倒置原則,具體工廠類的實例由工廠接口引用,具體產品的實例由產品接口引用。具體調用代碼如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package com.jasongj.client;

    import com.jasongj.bean.Product;
    import com.jasongj.bean.User;
    import com.jasongj.dao.role.IRoleDao;
    import com.jasongj.dao.user.IUserDao;
    import com.jasongj.dao.user.product.IProductDao;
    import com.jasongj.factory.IDaoFactory;
    import com.jasongj.factory.MySQLDaoFactory;

    public class Client {

    public static void main(String[] args) {
    IDaoFactory factory = new MySQLDaoFactory();

    IUserDao userDao = factory.createUserDao();
    User user = new User();
    user.setUsername("demo");
    user.setPassword("demo".toCharArray());
    userDao.addUser(user);

    IRoleDao roleDao = factory.createRoleDao();
    roleDao.getRole("admin");

    IProductDao productDao = factory.createProductDao();
    Product product = new Product();
    productDao.removeProduct(product);

    }

    }

    抽象工廠模式案例解析

    本文所述抽象工廠模式示例代碼可從作者Github下載

    上例是J2EE開發中常用的DAO(Data Access Object),操作對象(如User和Role,對應于數據庫中表的記錄)需要對應的DAO類。

    在實際項目開發中,經常會碰到要求使用其它類型的數據庫,而不希望過多修改已有代碼。因此,需要為每種DAO創建一個DAO接口(如IUserDao,IRoleDao和IProductDao),同時為不同數據庫實現相應的具體類。

    調用方依賴于DAO接口而非具體實現(依賴倒置原則),因此切換數據庫時,調用方代碼無需修改。

    這些具體的DAO實現類往往不由調用方實例化,從而實現具體DAO的使用方與DAO的構建解耦。實際上,這些DAO類一般由對應的具體工廠類構建。調用方不依賴于具體工廠而是依賴于抽象工廠(依賴倒置原則,又是依賴倒置原則)。

    每種具體工廠都能創建多種產品,由同一種工廠創建的產品屬于同一產品族。例如PostgreSQLUserDao,PostgreSQLRoleDao和PostgreSQLProductDao都屬于PostgreSQL這一產品族。

    切換數據庫即是切換產品族,只需要切換具體的工廠類。如上文示例代碼中,客戶端使用的MySQL,如果要換用Oracle,只需將MySQLDaoFactory換成OracleDaoFactory即可。

    抽象工廠模式優點

    • 因為每個具體工廠類只負責創建產品,沒有簡單工廠中的邏輯判斷,因此符合單一職責原則。
    • 與簡單工廠模式不同,抽象工廠并不使用靜態工廠方法,可以形成基于繼承的等級結構。
    • 新增一個產品族(如上文類圖中的MySQLUserDao,MySQLRoleDao,MySQLProductDao)時,只需要增加相應的具體產品和對應的具體工廠類即可。相比于簡單工廠模式需要修改判斷邏輯而言,抽象工廠模式更符合開-閉原則。

    抽象工廠模式缺點

    • 新增產品種類(如上文類圖中的UserDao,RoleDao,ProductDao)時,需要修改工廠接口(或者抽象工廠)及所有具體工廠,此時不符合開-閉原則。抽象工廠模式對于新的產品族符合開-閉原則而對于新的產品種類不符合開-閉原則,這一特性也被稱為開-閉原則的傾斜性。

    抽象工廠模式與OOP原則

    已遵循的原則

    • 依賴倒置原則(工廠構建產品的方法均返回產品接口而非具體產品,從而使客戶端依賴于產品抽象而非具體)
    • 迪米特法則
    • 里氏替換原則
    • 接口隔離原則
    • 單一職責原則(每個工廠只負責創建自己的具體產品族,沒有簡單工廠中的邏輯判斷)
    • 開閉原則(增加新的產品族,不像簡單工廠那樣需要修改已有的工廠,而只需增加相應的具體工廠類)

    未遵循的原則

    • 開閉原則(雖然對新增產品族符合開-閉原則,但對新增產品種類不符合開-閉原則)

    Java設計模式系列

    郭俊 Jason wechat
    歡迎關注作者微信公眾號【大數據架構】
    您的贊賞將支持作者繼續原創分享
    速赢彩app 威海 | 蓬莱 | 清徐 | 昌吉 | 醴陵 | 泰州 | 张家界 | 扬州 | 黄冈 | 贵港 | 阿克苏 | 长兴 | 清远 | 和田 | 任丘 | 长治 | 朔州 | 三沙 | 天长 | 克拉玛依 | 百色 | 大丰 | 双鸭山 | 阿拉善盟 | 河北石家庄 | 泸州 | 东阳 | 贵港 | 商洛 | 齐齐哈尔 | 高雄 | 佛山 | 寿光 | 金华 | 宁夏银川 | 大理 | 吐鲁番 | 乐平 | 潍坊 | 青州 | 赤峰 | 兴化 | 甘南 | 果洛 | 黄冈 | 铁岭 | 长兴 | 烟台 | 怀化 | 武威 | 大连 | 大同 | 防城港 | 长垣 | 邹平 | 潜江 | 迁安市 | 鸡西 | 忻州 | 安康 | 菏泽 | 无锡 | 济宁 | 安徽合肥 | 香港香港 | 塔城 | 马鞍山 | 顺德 | 上饶 | 浙江杭州 | 鸡西 | 长治 | 甘孜 | 蓬莱 | 长治 | 吉林长春 | 博尔塔拉 | 仁怀 | 随州 | 湖州 | 文山 | 德阳 | 正定 | 湖北武汉 | 五指山 | 大庆 | 瓦房店 | 芜湖 | 阜新 | 来宾 | 赤峰 | 安吉 | 海门 | 任丘 | 湖州 | 高雄 | 甘孜 | 赣州 | 永新 | 资阳 | 巴音郭楞 | 双鸭山 | 宝鸡 | 伊犁 | 台中 | 正定 | 改则 | 淮北 | 任丘 | 安吉 | 保亭 | 龙岩 | 高密 |