原创文章,同步发自作者个人博客,转载请注明出处 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. μC/OS-Ⅲ系统的源代码文件组织结构

  2. JavaScript 闭包系列二(匿名函数及函数的闭包)

    一. 匿名函数 1. 函数的定义,可分为三种 1) 函数声明方式 function double(x) {     return 2*x; } 2)Function构造函数,把参数列表和函数体都作为字 ...

  3. zynq学习01 新建一个Helloworld工程

    1,好早买了块FPGA板,zynq 7010 .终极目标是完成相机图像采集及处理.一个Window C++程序猿才开始学FPGA,一个小菜鸟,准备转行. 2,关于这块板,卖家的官方资料学起来没劲.推荐 ...

  4. 不使用ASP.NET中的服务器控件将如何上传文件?

    遇到文件的上传时,可能会有大部分的开发者喜欢使用服务器控件,虽然很方便,但是却不能很好的控制,不具灵活性. 现给出例子,使用html标签语言灵活的控制文件的上传. 1.html部分 <input ...

  5. CMT learning

    一个 GMT 命令由"gmt + 模块 + 选项 + 参数"构成,写成如下形式: gmt module -Axx+bxxxx -Bxx+axxxx • gmt 是 GMT 中&qu ...

  6. http 请求详解大全

    HTTP 100 Continue继续 101 Switching Protocols切换协议 200 OK正常 201 Created已创建 202 Accepted已接受 203 Non-Auth ...

  7. oracle问题

    (1) 连通性: 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇 ...

  8. java异常架构图 和几个面试题

    1.java异常架构图 粉红色的是受检查的异常(checked exceptions),其必须被 try{}catch语句块所捕获,或者在方法签名里通过throws子句声明.受检查的异常必须在编译时被 ...

  9. android assets文件夹浅谈

    ---恢复内容开始--- 最近在研究assets文件夹的一些属性跟使用方法.根据网上一些文章.实例做一下汇总,拿出来跟大家分享下,有不足的地方还请多多指教. 首先了解一下assets是干什么用的,as ...

  10. http数据返回值

    HTTP 400 - 请求无效HTTP 401.1 - 未授权:登录失败HTTP 401.2 - 未授权:服务器配置问题导致登录失败HTTP 401.3 - ACL 禁止访问资源HTTP 401.4 ...