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

原創文章,同步發自做者我的博客,轉載請註明出處 http://www.jasongj.com/design_pattern/abstract_factory/java

抽象工廠模式解決的問題

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

抽象工廠模式

抽象工廠模式介紹

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

抽象工廠模式類圖

抽象工廠模式類圖以下 (點擊可查看大圖)
數據庫

抽象工廠模式角色劃分

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

抽象工廠模式使用方式

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

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下載oop

上例是J2EE開發中經常使用的DAO(Data Access Object),操做對象(如User和Role,對應於數據庫中表的記錄)須要對應的DAO類。設計

在實際項目開發中,常常會碰到要求使用其它類型的數據庫,而不但願過多修改已有代碼。所以,須要爲每種DAO建立一個DAO接口(如IUserDao,IRoleDao和IProductDao),同時爲不一樣數據庫實現相應的具體類。代理

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

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

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

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

抽象工廠模式優勢

  • 由於每一個具體工廠類只負責建立產品,沒有簡單工廠中的邏輯判斷,所以符合單一職責原則。
  • 與簡單工廠模式不一樣,抽象工廠並不使用靜態工廠方法,能夠造成基於繼承的等級結構。
  • 新增一個產品族(如上文類圖中的MySQLUserDao,MySQLRoleDao,MySQLProductDao)時,只須要增長相應的具體產品和對應的具體工廠類便可。相比於簡單工廠模式須要修改判斷邏輯而言,抽象工廠模式更符合開-閉原則。

抽象工廠模式缺點

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

抽象工廠模式與OOP原則

已遵循的原則

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

未遵循的原則

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

Java設計模式系列

相關文章
相關標籤/搜索