设计模式之抽象工厂模式 _ JAVA
抽象工厂模式(英语:Abstract factory pattern)是一种软件开发设计模式。抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。客户端程序不需要知道(或关心)它从这些内部的工厂方法中获得对象的具体类型,因为客户端程序仅使用这些对象的通用接口。抽象工厂模式将一组对象的实现细节与他们的一般使用分离开来。
在以下情况可以考虑使用抽象工厂模式:
一个系统要独立于它的产品的创建、组合和表示时。
一个系统要由多个产品系列中的一个来配置时。
需要强调一系列相关的产品对象的设计以便进行联合使用时。
提供一个产品类库,而只想显示它们的接口而不是实现时。
优点
具体产品从客户代码中被分离出来
容易改变产品的系列
将一个系列的产品族统一到一起创建
缺点
在产品族中扩展新的产品是很困难的,它需要修改抽象工厂的接口
一个例子
要完成对数据库的交互,我们需要有一些共同的主题对象,Oracle数据库交互需要一个数据库连接对象,一个连接上下文对象和属性对象,而要与MySQL数据库交互,则需要一个MySQL连接对象,一个上下文对象和属性对象。
抽象工厂将单个工厂组合在一起而不指定具体类的工厂
AbstractFactory抽象工厂,聚合相同主题简单工厂
/** 数据库连接抽象工厂 */
public interface AbstractFactory {
Connection createConnection();// 数据库连接接口
Properties createProperties();// 属性接口
Context createContext();// 上下文接口
}OracleFactory类,实现抽象工厂类,创建Oracle数据库交互具体的对象
public class OracleFactory implements AbstractFactory{
@Override
public Connection createConnection() {
return new OracleConnection();
}
@Override
public Properties createProperties() {
return new OracleProperties();
}
@Override
public Context createContext() {
return new OracleContext();
}
}Context类,处理关于连接上下文信息
public interface Context {
/** 状态 */
String getStatus();
/** 上下文 */
List<Map> getContext();
}Connection类,连接对象
public interface Connection {
/** 打开连接 */
String open(Map properties);
/** 关闭连接 */
boolean close();
}Properties类,处理属性相关数据
public interface Properties {
MapgetProperties();
}OracleConnection类,继承自Connection。拥有打开和关闭数据库连接功能
public class OracleConnection implements Connection {
private boolean isOpen = false;
static final String message = "Open connection";
@Override
public String open(Map properties) {
setOpen(true);
return message;
}
@Override
public boolean close() {
if (isOpen()) setOpen(false);
return true;
}
public void setOpen(boolean open) { isOpen = open; }
public boolean isOpen() { return isOpen; }
}OracleContext类,继承自Context。处理连接状态,上下文信息
public class OracleContext implements Context {
private List<Map> mapList = new ArrayList<>();
protected OracleContext() {
Mapmap = new ConcurrentHashMap<>();
map.put("key", "context value");
mapList.add(map);
}
@Override
public String getStatus() { return "000 status"; }
@Override
public List<Map> getContext() { return mapList; }
}OracleProperties类继承自Properties,处理数据库交互参数信息
public class OracleProperties implements Properties {
private Map map;
protected OracleProperties() {
map = new HashMap<>();
map.put("username", "username");
map.put("password", "password");
map.put("drivername", "oracledriver");
}
@Override
public MapgetProperties() {
return map;
}
}抽象工厂模式提供了一种方法来封装具有共同主题的一组单独的工厂没有指定它们的具体类。在通常情况下,客户端软件创建一个具体的实现抽象工厂,然后使用工厂的通用接口来创建具体的对象主题。客户机不知道(或不关心)它从这些内部对象中获得哪些具体对象工厂,
因为它只使用其产品的通用接口。此模式分离了实现一组对象的一般用法,并依赖于对象组合,就像创建对象一样在工厂接口中公开的方法中实现。
抽象工厂模式的本质是工厂接口 AbstractFactory 及其实现(OracleFactory, MySQLFactory.
该示例使用两个具体实现来创建用于数据库交互的连接器,上下文以及属性对象。
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
private Context context;
private Connection connection;
private Properties properties;
/** 创建连接 */
public void createDatabase(final AbstractFactory factory) {
setConnection(factory.createConnection());
setContext(factory.createContext());
setProperties(factory.createProperties());
}
public static void main(String[] args) {
App app = new App();
// 创建Oracle数据库连接
app.createDatabase(FactoryMaker.makeFactory(FactoryMaker.FactoryType.ORACLE));
Mapproperties = app.getProperties().getProperties();
LOGGER.info(app.getConnection().open(properties));
LOGGER.info(app.getContext().getStatus());
LOGGER.info(app.getContext().getContext().toString());
LOGGER.info("isClose : "+app.getConnection().close());
// 创建MySQL数据库连接
app.createDatabase(FactoryMaker.makeFactory(FactoryMaker.FactoryType.MYSQL));
// do something
}
public static class FactoryMaker {
/** 枚举,不同类型的数据库连接 */
public enum FactoryType {
ORACLE // oracle数据库
,
MYSQL // mySql 数据库
}
/** 创建具体的工厂方法 */
public static AbstractFactory makeFactory(FactoryType type) {
switch (type) {
case MYSQL: // do create MySQLFactory...
case ORACLE: return new OracleFactory();
default: throw new IllegalArgumentException("DatabaseType not supported.");
}
}
}
public void setContext(Context context) { this.context = context; }
public void setConnection(Connection connection) { this.connection = connection; }
public void setProperties(Properties properties) { this.properties = properties; }
public Context getContext() { return context; }
public Connection getConnection() { return connection; }
public Properties getProperties() { return properties; }
}抽象工厂模式与工厂方法模式的区别
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
抽象工厂模式的扩展有一定的“开闭原则”倾斜性:
当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。
另外,当系统中只存在一个等级结构的产品时,抽象工厂模式可退化到工厂方法模式。
推荐阅读
-
4个理由告诉你Java为何排行第一
本文由码农网 –单劼原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!Java已经有20年的历史了,甚...
-
写给精明Java开发者的测试技巧
我们都会为我们的代码编写测试,不是吗?毫无疑问,我知道这个问题的答案可能会从“当然,但你知道怎样才能避免写测试吗?”到“必须...
-
Java 微服务框架 Redkale 入门介绍
Redkale功能Redkale虽然只有1.xM大小,但是麻雀虽小五脏俱全。既可作为服务器使用,也可当工具包使用。作为独立的工...
-
Java内存管理原理及内存区域详解
一、概述Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁...
-
2015年Java开发岗位面试题归类
下面是我自己收集整理的Java岗位今天面经遇到的面试题,可以用它来好好准备面试。一、Java基础1.String...
-
Java 虚拟机类加载机制和字节码执行引擎
引言我们知道java代码编译后生成的是字节码,那虚拟机是如何加载这些class字节码文件的呢?加载之后又是如何进行方法调用的呢?...
-
Java常量池理解与总结
一.相关概念什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态...
-
Java 实现线程死锁
概述春节的时候去面试了一家公司,笔试题里面有一道是使用简单的代码实现线程的‘死锁’,当时没有想到这道题考的是Sync...
-
Java:过去、未来的互联网编程之王
Java对你而言是什么?一门你大学里学过的语言?一个IT行业的通用语言?你相信Java已经为下一次互联网爆炸做好了准备么?Java...
-
20个高级Java面试题汇总
本文由码农网 –小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!这是一个高级Java面试系列题中...
