原创文章,转载请务必将下面这段话置于文章开头处(保留超链接)。
本文转发自技术世界,原文链接 http://www.jasongj.com/design_pattern/abstract_factory/
抽象工厂模式解决的问题
上文《工厂方法模式》中提到,在工厂方法模式中一种工厂只能创建一种具体产品。而在抽象工厂模式中一种具体工厂可以创建多个种类的具体产品。
抽象工厂模式
抽象工厂模式介绍
抽象工厂模式(Factory Method Pattern)中,抽象工厂提供一系列创建多个抽象产品的接口,而具体的工厂负责实现具体的产品实例。抽象工厂模式与工厂方法模式最大的区别在于抽象工厂中每个工厂可以创建多个种类的产品。
抽象工厂模式类图
抽象工厂模式类图如下 (点击可查看大图)
抽象工厂模式角色划分
抽象产品(或者产品接口),如上文类图中的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
31package 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即可。