乐趣区

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

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

退出移动版