设计模式学习笔记(五):工厂方法模式

1 前言

尽管简单工厂模式实现了对象的建立和使用分离,可是仍然存在如下两个问题:java

  • 工厂类过于庞大,包含了大量的判断代码,致使维护和测试难度增大
  • 系统扩展不灵活,若是增长了新的产品类型,必须修改静态工厂方法的业务逻辑,违反了开闭原则
  • 具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性

一个更好的办法是使用工厂方法模式。数据库

2 工厂方法模式

工厂方法模式:定义一个用于建立对象的接口,让子类决定将哪个类实例化。
工厂方法又简称工厂模式或虚拟构造器模式或多态工厂模式,让一个类的实例化延迟到其子类,是一种类建立型模式。
结构图以下:ide

在这里插入图片描述

工厂方法模式包含如下四个角色:性能

  • Product(抽象产品):定义产品的接口,是工厂方法模式所建立的超类型,也就是产品对象的公共父类
  • ConcreteProduct(具体产品):实现了抽象产品接口,某种类型的具体产品由专门的具体工厂建立,具体工厂与具体产品一一对应
  • Factory(抽象工厂):在抽象工厂类中,声明了工厂方法,用于返回一个产品。抽象工厂是工厂方法模式的核心,全部建立对象的工厂类都必须实现该接口
  • ConcreteFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例

3 实例

日志记录器的设计:该记录器能够经过多种途径保存系统的运行日志,例如文件记录或者数据库记录。测试

代码以下:this

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 总结

在这里插入图片描述

相关文章
相关标签/搜索