1 前言

只管简朴工厂模式实现了工具的建立和使用星散,然则仍然存在以下两个问题

  • 工厂类过于重大,包罗了大量的判断代码,导致维护和测试难度增大
  • 系统扩展不天真,若是增添了新的产物类型,必须修改静态工厂方式的营业逻辑,违反了开闭原则
  • 详细产物与工厂类之间的耦合度高,严重影响了系统的天真性和扩展性

一个更好的设施是使用工厂方式模式。

2 工厂方式模式

工厂方式模式:界说一个用于建立工具的接口,让子类决定将哪一个类实例化。
工厂方式又简称工厂模式或虚拟组织器模式或多态工厂模式,让一个类的实例化延迟到其子类,是一种类建立型模式。
结构图如下:

工厂方式模式包罗以下四个角色:

  • Product(抽象产物):界说产物的接口,是工厂方式模式所建立的超类型,也就是产物工具的公共父类
  • ConcreteProduct(详细产物):实现了抽象产物接口,某种类型的详细产物由专门的详细工厂建立,详细工厂与详细产物一一对应
  • Factory(抽象工厂):在抽象工厂类中,声明晰工厂方式,用于返回一个产物。抽象工厂是工厂方式模式的焦点,所有建立工具的工厂类都必须实现该接口
  • ConcreteFactory(详细工厂):它是抽象工厂类的子类,实现了抽象工厂中界说的工厂方式,并可由客户端挪用,返回一个详细产物类的实例

3 实例

日志纪录器的设计:该纪录器可以通过多种途径保留系统的运行日志,例如文件纪录或者数据库纪录。

代码如下:

public class Test
{
    public static void main(String[] args) {
        LoggerFactory factory = new FileLoggerFactory();        
        Logger logger = factory.createLogger();
        logger.log();
    }
}

//抽象产物
interface Logger
{
    void log();
}

//详细产物:DatabaseLogger
class DatabaseLogger implements Logger
{
    public void log()
    {
        System.out.println("数据库日志纪录");
    }
}

//详细产物:FileLogger
class FileLogger implements Logger
{
    public void log()
    {
        System.out.println("文件日志纪录");
    }
}

//抽象工厂
interface LoggerFactory
{
    Logger createLogger();
}

//详细工厂:DatabaseLoggerFactory
class DatabaseLoggerFactory implements LoggerFactory
{
    public Logger createLogger()
    {
        return new DatabaseLogger();
    }
}

//详细工厂:FileLoggerFactory
class FileLoggerFactory implements LoggerFactory
{
    public Logger createLogger()
    {
        return new FileLogger();
    }
}

4 隐藏

可以把抽象工厂设置为抽象类,工厂方式直接可以对客户端隐藏,也就是说可以直接通过抽象工厂挪用详细产物类的营业方式,客户端无需建立详细产物,直接通过工厂类挪用即可,代码修改如下(抽象产物以及详细产物类不用修改):

//抽象工厂
abstract class LoggerFactory
{
    public void log()
    {
        this.createLogger().log();
    }
    public abstract Logger createLogger();
}

//详细工厂:DatabaseLoggerFactory
class DatabaseLoggerFactory extends LoggerFactory
{
    public Logger createLogger()
    {
        return new DatabaseLogger();
    }
}

//详细工厂:FileLoggerFactory
class FileLoggerFactory extends LoggerFactory
{
    public Logger createLogger()
    {
        return new FileLogger();
    }
}

public class Test
{
    public static void main(String[] args) {
        LoggerFactory factory = new FileLoggerFactory();
        factory.log();
    }
}

5 主要优点

  • 封装细节:工厂方式用来建立客户所需要的产物,同时还向客户隐藏了哪种详细产物类将被实例化这一细节,用户只需体贴所需产物对应的工厂,无需体贴建立细节,甚至无须知道详细产物类的类名
  • 多态:工厂方式的多态性能够让工厂可以自主确定建立何种产物工具,而若何建立工具的细节则完全封装在详细工厂内部
  • 扩展性好:加入新产物时无须修改抽象工厂,抽象产物的接口,也无须修改客户端与其他的详细产物和详细工厂,只需要增添一个详细工厂以及详细产物,系统扩展性很好,完全符合开闭原则

6 主要瑕玷

  • 类数目多:在添加新产物时,需要编写新的详细产物类,而且还要提供与之对应的详细工厂类,系统中类的个数将成对增添,一定程度上增添了系统的复杂度,有更多的类需要编译和运行,给系统带来分外开销
  • 增添明白难度:基于系统的扩展性需要引入抽象层,在客户端中均使用了抽象层的界说,增添了系统的抽象性以及明白难度

7 适用场景

  • 客户端不知道其所需要的工具的类:在工厂方式模式中,客户端不需要知道详细的产物类名,只需要知道所对应的工厂即可
  • 抽象工厂类通过子类来指定建立哪个工具:工厂方式模式中,抽象工厂类只需要提供一个建立产物的接口,而有其子类来确定详细要建立的工具,行使面向工具的多态性和里氏代换原则,在程序运行时,子类工具将笼罩父类工具,从而使得系统加倍容易扩展

8 总结