原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/

抽象工厂模式解决的问题

上文《工厂方法模式》中提到,在工厂方法模式中一种工厂只能创建一种具体产品。而在抽象工厂模式中一种具体工厂可以创建多个种类的具体产品。

抽象工厂模式

抽象工厂模式介绍

抽象工厂模式(Factory Method Pattern)中,抽象工厂提供一系列创建多个抽象产品的接口,而具体的工厂负责实现具体的产品实例。抽象工厂模式与工厂方法模式最大的区别在于抽象工厂中每个工厂可以创建多个种类的产品。

抽象工厂模式类图

抽象工厂模式类图如下 (点击可查看大图)

抽象工厂模式角色划分

  • 抽象产品(或者产品接口),如上文类图中的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下载

上例是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设计模式系列

Java设计模式(三) 抽象工厂模式的更多相关文章

  1. java设计模式(三)--抽象工厂模式

    转载:http://zz563143188.iteye.com/blog/1847029 前面的工厂方法模式虽然清晰,但还是感觉有些繁琐,通常使用的还是抽象工厂模式. 工厂方法模式有一个问题就是,类的 ...

  2. Java 设计模式之抽象工厂模式(三)

    原文地址:Java 设计模式之抽象工厂模式(三) 博客地址:http://www.extlight.com 一.前言 上篇文章 <Java 设计模式之工厂模式(二)>,介绍了简单工厂模式和 ...

  3. java设计模式三种工厂模式简单介绍

    一.简单工厂模式 概述:简单工厂模式的创建意图就是,把对类的创建初始化全都交给一个工厂来执行,而用户不需要去关心创建的过程是什么样的,只用告诉工厂我想要什么就行了.而这种方法的缺点也很明显,违背了设计 ...

  4. Java设计模式系列-抽象工厂模式

    原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755412.html 一.概述 抽象工厂模式是对工厂方法模式的再升级,但是二者面对的场景稍显差别. ...

  5. java设计模式之抽象工厂模式

    上一篇文章(http://www.cnblogs.com/liaoweipeng/p/5768197.html)讲了简单工厂模式,但是简单工厂模式存在一定的问题,如果想要拓展程序,必须对工厂类进行修改 ...

  6. Java 设计模式之抽象工厂模式

    抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 在抽 ...

  7. java设计模式---三种工厂模式

    工厂模式提供创建对象的接口. 工厂模式分为三类:简单工厂模式(Simple Factory), 工厂方法模式(Factory Method)和抽象工厂模式(Abstract Factory).GOF在 ...

  8. Java设计模式(3)——抽象工厂模式

    抽象工厂模式是所有形态的工厂模式中最为抽象和最其一般性的.抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象. 一.产品族和产品等级结构 为 ...

  9. [java] java 设计模式(2):抽象工厂模式(Abstract Factory)

    工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这 ...

  10. java设计模式之抽象工厂模式学习

    工厂模式有个问题就是,类的创建依赖工厂.要想增加一个工厂类,就要修改原来的代码,这违背了闭包原则.所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的 ...

随机推荐

  1. 线程隔离ThreadLocal

    ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地 ...

  2. Flapper Bird的学习笔记(二)

    因为有一个超屌的梦想,所以就绝不会做一个孬种的追梦人! 本章节主要目的: 实现小鸟的飞行. 实现管道的随机出现. 实现相机跟随. 上次主要是场景的布置,这节全力拿下代码. 1.小鸟飞行(一种制作2D动 ...

  3. [转载]Three Trending Computer Vision Research Areas, 从CVPR看接下来几年的CV的发展趋势

    As I walked through the large poster-filled hall at CVPR 2013, I asked myself, “Quo vadis Computer V ...

  4. bzoj 3172 单词 ac自动机|后缀数组

    题目大意: 给定n个字符串连成了一篇文章,问每个字符串在这篇文章中出现的次数,可重复覆盖 这里ac自动机和后缀数组都可以做 当然后缀数组很容易就解决,但是相对时间消耗高 这里就只讲ac自动机了 将每个 ...

  5. 记第一次TopCoder, 练习SRM 583 div2 250

    今天第一次做topcoder,没有比赛,所以找的最新一期的SRM练习,做了第一道题. 题目大意是说 给一个数字字符串,任意交换两位,使数字变为最小,不能有前导0. 看到题目以后,先想到的找规律,发现要 ...

  6. android-studio的gradle plugin配置相关的一些记录

    感觉就是越高的Gradle版本对应的plugin越高. 你妹的,是不是2.10版本低于2.2版本,我还以为是2.10版本高于2.8.2.9版本呢.每次用2.10版本构建,用1.2.2等都不行.提示最低 ...

  7. app启动时间命令

    app启动: 冷启动和热启动 冷启动方式: adb shell am start -W -n package/activity 停止app命令: adb shell am force-stop pac ...

  8. Percona Server 5.6.33-79.0 发布

    Percona Server 5.6.33-79.0 发布了,该版本基于 MySQL 5.6.33,包含了所有的 bug 修复,是Percona Server 5.6 系列中的正式版本.该版本主要是修 ...

  9. clip:rect矩形剪裁

    clip:rect(top right bottom left);依据上-右-下-左的顺序提供自图片左上角为(0,0)坐标计算的四个偏移数值,其中任一数值都可用auto替换. 矩形剪裁 还需要绝对定位 ...

  10. odi 12.2.1.1新特性

    ODI 12.2.1.1现在已经发布,也可以OTN上下载,主要变化: Hyperion Essbase and Hyperion Planning 知识模块 Hyperion Essbase and ...