定义:

提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。

结构:(书中图,侵删)

这个图相对来说有一点点复杂,其实就是在工厂方法模式的基础上做了一些扩展,工厂方法模式只用于生成一种产品(把上图ProductB相关的都去掉就是了),而抽象工厂模式可用于生产多种产品。
加上例子吧,假设生产海贼的手办(路飞和娜美)。
一个抽象工厂抽象接口(包含生成所有类型产品的方法,即生成路飞和娜美的方法)
若干个具体工厂(各种生成产品的不同实现的工厂,理论上,同一个具体工厂底下生成的都是同一个系列的产品。类似于A工厂生成两年前的,B工厂生成两年后的,生成出来的都是同一个人物)
若干个抽象的产品接口(这里就是路飞和娜美两个)
每个抽象的产品接口下有若干个具体的产品类(路飞下有(两年前路飞、两年后路飞);娜美下有(两年前娜美,两年后娜美))
根据上例照着原格式再来画张图,便于理解:(把client去掉了,懒得画)

实例:

鉴于书中的例子相当的常见,所以决定延用书中的例子。
就是更换数据库的例子。
假设系统中有员工、部门两个类。
然后系统需要使用mysql和oracle两个数据库。
为了代码简洁,不分什么dao层之类的,直接把调用数据库的方法写在实体里。
员工抽象类:

package designpattern.abstractfactory;

public abstract class Employee {
private String name; abstract void insert(Employee employee); public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Employee [name=" + name + "]";
} }
oracle员工类:

package designpattern.abstractfactory;

public class OracleEmployee extends Employee {

    @Override
void insert(Employee employee) {
System.out.println("往oracle数据库插入一条Employee员工数据:" + employee);
} }
mysql员工类:

package designpattern.abstractfactory;

public class MysqlEmployee extends Employee {
@Override
public void insert(Employee employee) {
System.out.println("往mysql数据库插入一条Employee员工数据:" + employee);
} }
部门抽象类:

package designpattern.abstractfactory;

public abstract class Department {
String name; abstract void insert(Department department); public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Department [name=" + name + "]";
} }
oracle部门类:

package designpattern.abstractfactory;

public class OracleDepartment extends Department {

    @Override
void insert(Department department) {
System.out.println("往oracle数据库插入一条Department部门数据:" + department);
} }
mysql部门类:

package designpattern.abstractfactory;

public class MysqlDepartment extends Department {

    @Override
void insert(Department department) {
System.out.println("往mysql数据库插入一条Department部门数据:"+department);
} }
抽象工厂类:

package designpattern.abstractfactory;

public interface Factory {
Employee createEmployee(); Department createDepartment();
}
mysql工厂类:

package designpattern.abstractfactory;

public class MysqlFactory implements Factory {

    @Override
public Employee createEmployee() {
return new MysqlEmployee();
} @Override
public Department createDepartment() {
return new MysqlDepartment();
} }
oracle工厂类:

package designpattern.abstractfactory;

public class OracleFactory implements Factory {

    @Override
public Employee createEmployee() {
return new OracleEmployee();
} @Override
public Department createDepartment() {
return new OracleDepartment();
} }
客户端:

package designpattern.abstractfactory;

public class Client {
public static void main(String[] args) {
Factory factory = new MysqlFactory();
// Factory factory=new OracleFactory(); Employee employee = factory.createEmployee();
employee.setName("张三");
employee.insert(employee); Department department = factory.createDepartment();
department.setName("技术部");
department.insert(department); }
}
结果输出:

往mysql数据库插入一条Employee员工数据:Employee [name=张三]
往mysql数据库插入一条Department部门数据:Department [name=技术部]
这个设计模式很好的解除了客户端与实例创建过程的耦合,通过抽象出接口的方式,使客户端只需要和接口打交道。
同时也使得切换数据库变得容易,只需要修改初始化的语句即可。
这同样也是这个模式的不足之处,意味着所有需要用到数据库连接的地方都要写上这句初始化语句,使得修改的工作量变得很大。
 
接下来就一步一步优化它:
首先,使用哪个数据库的判断是在客户端,我们需要把这个判断转移,使用简单工厂模式,将判断转移至简单工厂:
简单工厂:

package designpattern.abstractfactory;

public class SimpleFactory {
static String db = "mysql";
//static String db="oracle"; static Employee createEmployee() {
switch (db) {
case "mysql":
return new MysqlEmployee();
case "oracle":
return new OracleEmployee();
default:
return null;
}
} static Department createDepartment() {
switch (db) {
case "mysql":
return new MysqlDepartment();
case "oracle":
return new OracleDepartment();
default:
return null;
}
} }
客户端:

package designpattern.abstractfactory;

public class Client2 {
public static void main(String[] args) {
Employee employee = SimpleFactory.createEmployee();
employee.setName("张三");
employee.insert(employee); Department department = SimpleFactory.createDepartment();
department.setName("技术部");
department.insert(department); }
}
然后,如果再增加一个数据库,需要在所有的方法里增加switch的case,这也是很麻烦的事情,这里需要用到反射来解决这个问题:
反射版简单工厂:

package designpattern.abstractfactory;

public class ReflectSimpleFactory {
static String db = "Mysql";
// static String db="Oracle"; static String path = "designpattern.abstractfactory";// 包路径 static Employee createEmployee() {
try {
Class<Employee> employee = (Class<Employee>) Class.forName(path + "." + db + "Employee");
return employee.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
} static Department createDepartment() {
try {
Class<Department> department = (Class<Department>) Class.forName(path + "." + db + "Department");
return department.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
} }
客户端:

package designpattern.abstractfactory;

public class Client3 {
public static void main(String[] args) {
Employee employee = ReflectSimpleFactory.createEmployee();
employee.setName("张三");
employee.insert(employee); Department department = ReflectSimpleFactory.createDepartment();
department.setName("技术部");
department.insert(department); }
}
通过反射,将程序由编译时改为运行时,彻底取代了switch语句。
 
现在,还剩最后一个问题,决定使用什么数据库的字符串还是写在代码中,修改之后还需要重新编译,这里只需要把字符串改到配置文件中即可:
简单工厂:

package designpattern.abstractfactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties; public class ReflectSimpleFactory2 { static String path = "designpattern.abstractfactory";// 包路径 static Employee createEmployee() {
try {
Class<Employee> employee = (Class<Employee>) Class.forName(path + "." + getDBName() + "Employee");
return employee.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
} static Department createDepartment() {
try {
Class<Department> department = (Class<Department>) Class.forName(path + "." + getDBName() + "Department");
return department.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
} private static String getDBName() {
String dbName = null;
try {
InputStream in = ReflectSimpleFactory2.class.getResourceAsStream("db.properties");
Properties pro = new Properties();
pro.load(in);
in.close();
dbName = pro.getProperty("db");
} catch (IOException e) {
e.printStackTrace();
} return dbName; }
}
配置文件:

db=Mysql
#db=Oracle
客户端:

package designpattern.abstractfactory;

public class Client4 {
public static void main(String[] args) {
Employee employee = ReflectSimpleFactory2.createEmployee();
employee.setName("张三");
employee.insert(employee); Department department = ReflectSimpleFactory2.createDepartment();
department.setName("技术部");
department.insert(department); }
}
大功告成!
 

总结:

抽象工厂设计模式和其他的工厂类设计模式一样,就是将客户端与具体的对象创建过程分离。
只不过这里所涉及到的不再是一种类,而是多种类,结构相对复杂。
同时也像上文说的一样,存在一些不足,可以具体情况具体分析,应该如何使用。
 

设计模式 | 抽象工厂模式(abstract factory)的更多相关文章

  1. 设计模式 - 抽象工厂模式(abstract factory pattern) 具体解释

    抽象工厂模式(abstract factory pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/2709 ...

  2. C#设计模式——抽象工厂模式(Abstract Factory Pattern)

    一.概述在软件开发中,常常会需要创建一系列相互依赖的对象,同时,由于需求的变化,往往存在较多系列对象的创建工作.如果采用常规的创建方法(new),会造成客户程序和对象创建工作的紧耦合.对此,抽象工厂模 ...

  3. Objective-C设计模式——抽象工厂模式Abstract Factory(对象创建)

    抽象工厂模式 理解了工厂方法模式,其实抽象工厂和工厂方法模式有很多的相似之处.抽象工厂同样是分离客户端对象的创建和逻辑代码的,但是抽象工厂往往是产生一组数据而不单单是产生一个产品. 抽象工厂提供一个创 ...

  4. 大话设计模式--抽象工厂模式 Abstract Factory -- C++实现实例

    1. 抽象工厂模式: 提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体的类. 下面是工厂方法模式: 下面是抽象工厂模式: 和工厂方法模式相比 抽象工厂模式可以有多个Product抽象, ...

  5. 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)

    原文:乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factor ...

  6. 【设计模式】抽象工厂模式 Abstract Factory Pattern

    简单工厂模式是一个工厂类根据工厂方法的参数创建不出不同的产品, 工厂方法模式是每一个产品都有一个一一对应的工厂负责创建该产品.那么今天要讲的抽象工厂模式是一个工厂能够产生关联的一系列产品.抽象工厂模式 ...

  7. .NET设计模式(2):1.2 抽象工厂模式(Abstract Factory)

    概述 抽象工厂模式(Abstract Factory)是所有形态的工厂模式中最为抽象和最具一般性的一种形态.抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式.抽象工厂模式可以向客户端提供一个接口 ...

  8. 二十四种设计模式:抽象工厂模式(Abstract Factory Pattern)

    抽象工厂模式(Abstract Factory Pattern) 介绍提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 示例有Message和MessageModel,Messag ...

  9. 【UE4 设计模式】抽象工厂模式 Abstract Factory Pattern

    概述 描述 提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类:具体的工厂负责实现具体的产品实例 抽象工厂中每个工厂可以创建多种产品(如苹果公司生产iPhone.iPad): 工厂方法 ...

  10. 抽象工厂模式(Abstract Factory)C#实例

    抽象工厂模式(Abstract Factory)C#实例 本文出处http://www.dofactory.com/net/abstract-factory-design-pattern 一.场景描述 ...

随机推荐

  1. Centos6离线安装MySQL5.5.55-1(附带安装包及Perl依赖包)

    资源包下载https://pan.baidu.com/s/1U3myYp4GSmDUfZocMWI9FA 密码:xdac 资源包所带有的资源截图 1.上传MySQL-client-5.5.55-1.l ...

  2. MySql的下载和安装(解压版)

    工具/原料   windows系统 一.Mysql的下载     打开浏览器,输入mysql,点击百度搜索,得到搜索结果.   在搜索结果中,选择下面结果,因为浏览器的不同,Mysql官网在搜索结果的 ...

  3. eclipse 创建maven web示例

    注意,以下所有需要建立在你的eclipse等已经集成配置好了maven了,没有的话需要安装maven. 一.创建项目 1.新建maven项目,如果不在上面,请到other里面去找一下 一直点击下一步, ...

  4. Hibernate入门----配置文件

    一.Hibernate简介 hibernate是一个开源的,轻量级的,持久成ORM框架. Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数 ...

  5. Tiny4412之蜂鸣器驱动与led灯驱动

    一:LED驱动编写 要编写LED驱动,首先的知道开发板的构造:开发板分为核心板与底板:编写驱动的第一步就是要看开发板,找到LED灯在开发板上的位置及所对应的名字:第一步就要查看核心板电路图,以及底板电 ...

  6. echart css样式弄了几个月了,样式一直都没有好好解决,好激动

    legend 图例,每个图表最多仅有一个图例.try this » 名称 默认值 描述 {string} orient 'horizontal' 布局方式,默认为水平布局,可选为:'horizonta ...

  7. 使用单进程、strace、gdb调试PHP错误

    使用单进程.strace.gdb调试PHP错误 PHP一般是在FPM的呵护下运行的,但是某些情况下进程异常崩溃会导致502.下面是解决思想: 1. 单进程运行: php -d display_erro ...

  8. Python +selenium自动化环境的搭建

    Python +selenium+googledriver 小白的血泪安装使,不停的总结写心得是理解透彻的毕竟之路 一,python的安装: 首先去Python的官网下载安装包:https://www ...

  9. Scrapy 1.4 文档 05 命令行工具

    在系统命令行中,使用 scrapy 命令可以创建工程或启动爬虫,它控制着 Scrapy 的行为,我们称之为 Scrapy 命令行工具(command-line tool)或 Scrapy 工具(Scr ...

  10. 通过配置tomcat实现项目免部署

    对于一些比较大的项目,比如说使用了EXTJS这种重量级UI框架的项目,在部署的时候,eclipse会卡崩的,所以可以通过配置tomcat来实现免部署,直接运行即可: 首先找到tomcat的localh ...