1. 优享JAVA首页
  2. Java
  3. 设计模式

设计模式之抽象工厂模式

抽象工厂模式意图是提供一种方法来封装一组具有公共主题的单独工厂,而无需指定他们的具体类

抽象工厂模式(英语: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<String, Object>> getContext();
}

Connection类,连接对象

public interface Connection {
    /** 打开连接 */
    String open(Map properties);
    /** 关闭连接 */
    boolean close();
}

Properties类,处理属性相关数据

public interface Properties {
    Map<String, Object> getProperties();
}

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<String, Object>> mapList = new ArrayList<>();

    protected OracleContext() {
        Map<String, Object> map = new ConcurrentHashMap<>();
        map.put("key", "context value");
        mapList.add(map);
    }

    @Override
    public String getStatus() { return "000 status"; }

    @Override
    public List<Map<String, Object>> 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 Map<String, Object> getProperties() {
        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));
        Map<String, Object> properties = 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; }
}

抽象工厂模式与工厂方法模式的区别

抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。

抽象工厂模式的扩展有一定的“开闭原则”倾斜性:

  • 当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
  • 当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。

另外,当系统中只存在一个等级结构的产品时,抽象工厂模式可退化到工厂方法模式。

原创文章,作者:Craig,如若转载,请注明出处:https://www.goodlymoon.com/archives/1288.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注

QR code