Java设计模式再相识 (四)——抽象工厂(Abstract Factory)模式

11 篇文章 0 订阅
11 篇文章 0 订阅

上节我们详细介绍了工厂方法模式,解决了复杂对象的创建问题。这次,我们的需求再次升级,我们需要生成具有层级关系的具体产品,并且同一层级具有由多个具体工厂生产的具体产品。对比工厂方法模式,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

抽象工厂模式

抽象工厂(Abstract Factory)模式:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,同样属于对象创建型模式。

抽象工厂模式的结构与工厂方法类似,只不过在原有的基础上拓展了层级概念。

  • 抽象工厂(AbstractFactory):提供了产品的抽象类或接口。
  • 具体工厂(ConcreteFactory):具体的创建类,实现具体生产产品的方法。
  • 抽象产品(Product):产品的抽象创建类。
  • 具体产品(ConcreteProduct):将抽象产品进行实现。

实际应用场景

换行符:在不同操作系统中,换行符也各有不同。像在Windows下,换行符是\r\n,而在Linux下则是\n。在这个场景中,操作系统充当一个超级工厂角色,Windows和Linux则是超级工厂下的具体工厂,换行符则是它们生产的具体产品。

数据库:不同的数据库有自己的数据库方言,但它们的基础都是SQL语言。

示例

在本文中,与上篇一样,我们还是采用日志工厂进行举例。

在抽象日志工厂中,我们有一个超级工厂,也就是日志工厂。日志工厂下面有两个小工厂,分别是Log4j工厂和Logback工厂,这两个工厂可以生产出不同风格的日志。同时我们日志的产品有:直接输出到控制台的日志,写入文件的日志。两个工厂实现日志的逻辑各不相同。下面我们开始写具体的代码。

首先我们先来创建超级工厂类。

Factory.java


package com.yeliheng.factory.abstractfactory;

/**
 * 超级工厂
 */
public interface Factory {

    public ConsoleLogger consoleLogger();

    public FileLogger fileLogger();

}


超级工厂类中提供了两个接口:分别是控制台日志接口和文件接口。它告诉下面的工厂,只能生产这两种接口规范的产品。具体怎么进行生产,超级工厂并不关心。

然后,我们创建两家工厂,分别是Log4j工厂和Logback工厂。

Log4jFactory.java


package com.yeliheng.factory.abstractfactory;

/**
 * Log4j工厂
 */
public class Log4jFactory implements Factory{
    @Override
    public ConsoleLogger consoleLogger() {
        return new Log4jConsoleLogger();
    }

    @Override
    public FileLogger fileLogger() {
        return new Log4jFileLogger();
    }
}

LogbackFactory.java


package com.yeliheng.factory.abstractfactory;

/**
 * Logback工厂
 */
public class LogbackFactory implements Factory{

    @Override
    public ConsoleLogger consoleLogger() {
        return new LogbackConsoleLogger();
    }

    @Override
    public FileLogger fileLogger() {
        return new LogbackFileLogger();
    }
}

在这两家工厂中,我们实现了超级工厂提供的两个方法,并让其返回自身生产的具体产品类。

我们先来实现抽象的产品类。

ConsoleLogger.java

package com.yeliheng.factory.abstractfactory;

/**
 * 抽象产品类: 控制台日志
 */
public interface ConsoleLogger{

    //日志级别

    void debug(String text);

    void info(String text);

    void warning(String text);

    void error(String text);

}

FileLogger.java


package com.yeliheng.factory.abstractfactory;

/**
 * 抽象产品类: 文件日志
 */
public interface FileLogger{

    //日志级别
    void debug(String text);

    void info(String text);

    void warning(String text);

    void error(String text);
}

这两个抽象产品类都提供了四种不同级别的日志输出,分别是debug,info,warning,error。你会发现它们内容相同。在实际开发中,我们需要根据实际需求对其代码进行修改。这里为了方便演示与理解,仅仅通过名字和输出来区别“输出到控制台的日志”和“输出到文件的日志”,并没有真正使用文件流来将日志保存到磁盘。

现在,我们可以开始实现具体的产品类了。

Log4jConsoleLogger.java

package com.yeliheng.factory.abstractfactory;

/**
 * 具体产品类
 */
public class Log4jConsoleLogger implements ConsoleLogger{
    @Override
    public void debug(String text) {

    }

    @Override
    public void info(String text) {
        System.out.println("--[INFO]-- Log4j输出的[控制台]日志: " + text);
    }

    @Override
    public void warning(String text) {

    }

    @Override
    public void error(String text) {

    }
}

Log4jFileLogger.java

package com.yeliheng.factory.abstractfactory;

/**
 * 具体产品类
 */
public class Log4jFileLogger implements FileLogger{
    @Override
    public void debug(String text) {

    }

    @Override
    public void info(String text) {
        System.out.println("--[INFO]-- Log4j输出的[文件]日志: " + text);
    }

    @Override
    public void warning(String text) {

    }

    @Override
    public void error(String text) {

    }
}

在具体产品类中,我们通过输出风格的不同来区别是Log4j工厂还是Logback工厂生产的产品。
LogbackConsoleLogger.java和LogbackFileLogger.java的内容与Log4j的具体产品内容基本相同,仅仅只有输出的不同。完整的代码可前往Github获取。

准备好了工厂和产品,这个时候客户来了。客户要开始使用工厂生产出来的产品了。

我们开始编写Main类,以便于使用我们刚才写好的代码,让工厂开始工作。

Main.java


package com.yeliheng.factory.abstractfactory;

public class Main {
    public static void main(String[] args) {
        Factory log4jFactory = new Log4jFactory();
        ConsoleLogger consoleLogger = log4jFactory.consoleLogger();
        consoleLogger.info("测试日志");

        FileLogger fileLogger = log4jFactory.fileLogger();
        fileLogger.info("文件测试");

        Factory logbackFactory = new LogbackFactory();
        ConsoleLogger consoleLogger1 = logbackFactory.consoleLogger();
        consoleLogger1.info("测试日志");

        FileLogger fileLogger1 = logbackFactory.fileLogger();
        fileLogger1.info("文件测试");


    }
}

在Main方法中,我们分别对两家工厂生产的同一级别的四种产品进行测试。最后我们查看运行结果。

output.png

从运行结果可以看出,两家日志工厂都正确地输出了各自生产的日志,这就是抽象工厂模式的具体实现。

抽象工厂模式的优缺点

优点:

  • 能够生成复杂的,多个层级的产品结构。
  • 隔离了具体类的生成:系统不用关心具体产品如何创建,组合。这在项目开发中能够维持良好的拓展性。

缺点:

  • 层级较为复杂带来的就是系统复杂性的提高。
  • 开闭原则的倾斜性:增加新的工厂和产品等级结构容易,增加新的同级的产品需要改变工厂代码。

总结

抽象工厂模式在简单工厂和工厂方法的基础上进行升级,最重要的是类层级结构的产生,可以使调用者无需关心什么对象被创建,提高系统的内聚性。

本例完整的源码可参见: Github

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值