1 解释
1.1 定义
提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
1.2 分析
抽象工厂类似工厂模式,都有工厂类。区别在于,抽象工厂创建的是一系列的产品;而工厂方法只是创建一个产品。
什么是相关和相互依赖,这个类似于产品族的概念。位于不同产品等级结构,功能相关联的产品组成的家族就是产品族。如下图,入门级中的QQ、别克、奔驰他们都有类似的功能和用途,所以他们都是一个产品族的成员。
将抽象工厂套用下面的例子,抽象工厂提供了创建QQ、别克、奔驰的接口,由子类来决定创建哪个产品族的车辆。
1.3 举例
数据库中的Mysql,Sql,Access也是不同的产品族,其中的插入、删除、查找等操作就是不同的产品等级。抽象工厂提供了创建插入、删除、查找等操作的接口,由子类决定实例化为哪种数据库的操作。
界面换主题功能也如此,主题中有典雅、流行、清新这些产品族,主界面、按钮、图标等是相关联相互依赖的组件。抽象工厂提供创建一系列组件的接口,比如主界面、按钮、图标的接口,由子类解决实例化为哪种主题的组件。
1.4 优势
当我们需要批量切换产品的时候,他可以减少N多工作量,大大降低再次开发的难度。
一个系统原来使用Sql,现在需要改为Mysql。假如使用了抽象工厂,我们只需要将实现部分再写一遍,然后在代码中切换到Sql的实例化即可。否则,我们要在每处调用的地方做修改。
一个应用程序原来在平台A上使用,现在需要兼容平台B。如果使用了抽象工厂,我们只需要将平台差异的接口实现一遍,然后在代码中实例化对应的平台接口就可以了。否则,代码中导出都是if else判断。
2 代码实例
2.1 模型类图
抽象工厂(AbstractFactory):核心部分,定义了具体工厂必须实现的接口或者必须继承的类。他可以是接口,也可以是抽象类。
具体工厂(ConcreteFactory):提供方法给程序调用,返回产品实例。
抽象产品(AbstractProduct):工厂方法中所创建对象的父类或者接口,具体产品的父类。
具体产品(Product):程序最终需要的东西,这里有各种我们需要的方法。
2.2 代码实例的类图
在ICreateDatabaseFactory(抽象工厂)中,定义了创建操作表User和Department的实体类的接口。
SqlFactory, MysqlFactry(具体工厂)分别实现抽向工厂定义的接口,分别返回Sql和Mysql的DAO。
IUserDAO, IDepartmentDAO(抽象产品)定义了具体的操作插入和查询。
XXXDAO(具体产品)实现对应的DAO的操作,如插入和查询。
2.3 代码实例
一个main函数,说明抽象工厂如何调用。
public class AbstractFactoryTest {
public static void main(String[] args) {
// Choose different database here.
// ICreateDataBaseFactory factory = new SqlFactory();
ICreateDataBaseFactory factory = new MysqlFactory();
IUserDAO userDAO = factory.createDatabaseUser();
userDAO.insert();
userDAO.getUserName();
}
}
首先是工厂类,返回了操作不同表的接口。
public interface ICreateDataBaseFactory {
IUserDAO createDatabaseUser();
IDepartmentDAO createDatabaseDepartment();
}
针对Mysql数据库,实现抽象工厂的接口,返回操作表的实体类。
public class MysqlFactory implements ICreateDataBaseFactory {
@Override
public IUserDAO createDatabaseUser() {
return new MysqlUserDAO();
}
@Override
public IDepartmentDAO createDatabaseDepartment() {
return new MysqlDepartmentDAO();
}
}
同MysqlFactory类似,针对Sql数据库,实现抽象工厂的接口,返回操作表的实体类。
public class SqlFactory implements ICreateDataBaseFactory {
@Override
public IUserDAO createDatabaseUser() {
return new SqlUserDAO();
}
@Override
public IDepartmentDAO createDatabaseDepartment() {
return new SqlDepartmentDAO();
}
}
定义操作数据库User这个表的具体接口。
public interface IUserDAO {
void insert();
void getUserName();
}
实现Mysql操作User表的方法。
public class MysqlUserDAO implements IUserDAO {
@Override
public void insert() {
System.out.println("Mysql insert data to user");
}
@Override
public void getUserName() {
System.out.println("Mysql get data from user");
}
}
同MysqlUserDAO类似,实现Sql操作User表的方法。
public class SqlUserDAO implements IUserDAO {
@Override
public void insert() {
System.out.println("Sql insert data to user");
}
@Override
public void getUserName() {
System.out.println("Sql get data from user");
}
}
同IUserDAO类似,定义操作Department表的方法。
public interface IDepartmentDAO {
void insert();
void getDepartmentName();
}
实现Mysql中对表Department操作的方法。
public class MysqlDepartmentDAO implements IDepartmentDAO {
@Override
public void insert() {
System.out.println("Mysql insert data to department");
}
@Override
public void getDepartmentName() {
System.out.println("Mysql get data from department");
}
}
同MysqlDepartmentDAO,实现Sql中对表Department操作的方法。
public class SqlDepartmentDAO implements IDepartmentDAO {
@Override
public void insert() {
System.out.println("Sql insert data to department");
}
@Override
public void getDepartmentName() {
System.out.println("Sql get data from department");
}
}
代码下载地址:https://github.com/bird7310/DesignPatternExample.git
3 其他
更新间隔有些慢,下次要加快速度。
不时会看前面写的《工厂方法》,发现写的不怎么好。写这一篇的时候也是在不断思考如何能让大家很容易很轻松很很愉快的学习设计模式。后续文章行文会不断的改变,目的就是找到一个合适的方式方便大家学习。
计划先把每一种模式讲解一遍,然后再专门做具体情境分析的专题。
希望大家多提意见,一起学习一起成长。