Java设计模式——工厂方法模式

1.应用场景

考虑以下场景:一个文本处理工具,用户写了一部分内容,要将文本输出到一个文件中,这个文件的格式不知道,而且可能会在写文件的时候对用户的文本进行编码等处理。

首先,对用户可能写的每一个文件,都要写一个文件对象,这些文件对象实现同一个接口
Java设计模式——工厂方法模式

接下来写用户部分,用户要创建相关的文件并且写入。这时考虑到Document的类型随时可以添加。
Java设计模式——工厂方法模式
其中,writeintodoc要完成的功能是,创建或打开一个文件,按该文件的写入方式进行写入。

所以,writeintodoc应当创建一个Document对象(创建Document对象的过程,可以直接调用createdoc()方法),然后按该文件的格式编码等写入。这时遇到了问题

User的writedoc()方法必须知道创建了哪个对象才能继续写下去,但是使用这个User类的人可能想写任何一种文件,只有他给了命令后才能知道他具体想写入到哪一种文件,无法提前预知,产生了尴尬的局面。

为了解决这个问题,可以将它分成两部分看,一部分是Document文件如何写入,一部分是writeintodoc()的不同逻辑如何实现。

不同Document文件的不同写入比较容易实现,只要利用多态就好了。每个子类有对应的open,write,close等方法,利用createdoc()传出的Document对象和多态机制,可以执行相应的功能。

writeintodoc()的不同逻辑如何实现,只要调用上边提到的多态的方法就可以,但是,如何得到这个Document对象。

一种想法是,从createdoc()中传入一个字符串或枚举参数,传入创建文件的类型。字符串传入可能会导致不安全,可能内部需要再处理。如果是枚举传入安全性得到提高,也是一种好方法。不过,如果文件种类非常多,且要加入对文件的修饰,就可能会导致组合爆炸

比如,DOC类文档可以加入普通文本直接输入的,用某些模板的,文字处理的,HTML可以加入使用各种框架的,等等。且他们之间还可以发生组合,例如,用某个模板并且要对文字进行加粗处理且使用某个框架的DOC,这样会出现非常多的类型,枚举类型将变得很复杂。

如果有一种方法,需要什么类型就添加什么类型,问题就会简化一些。对上边的枚举进行改良,只加入需要的类型。这样每次加入新类型,枚举都要进行修改。而且,在createdoc()中也会不断的删改代码。这样可能会导致createodoc()变的冗长且难以维护。

下边考虑使用工厂方法进一步简化这个问题

将createdoc()抽象化,如果在createdoc()一个方法中处理所有文件的情况,可能会由于所有代码都写入一个方法,判断语句复杂等等问题造成麻烦。所以考虑将createdoc()的代码分散。所有继承User的子类共同来完成createdoc()的逻辑。这样,需要一个新的种类的文档,只需要在Document加一种实现,然后User加一个子类,实现createdoc()方法即可。这样做逻辑变得简单清晰。

由于多态的性质,其子类调用createdoc()方法时就会自动的调用相应方法,这样writeintodoc()方法中createdoc()方法的实现就会自动关联相应的方法。其创建出的对象由于多态又会自动执行对应的open(),write(),close().

Java设计模式——工厂方法模式

2.适用情况

  1. 必须要创建某个对象,只能确定该对象泛化的情况(抽象类或接口),而不能确定具体类
  2. 必须要创建某个对象,能确定泛化的对象,而希望子类来指定具体类
  3. 创建对象的工作委托给子类完成,创建逻辑由子类负责补全

3.抽象工厂的结构

Java设计模式——工厂方法模式

4.工厂方法的拓展

1)缺省实现

给抽象类中的抽象方法一个具体实现,这样工厂方法可以表现为功能扩展的方法。

2)职责委托代理

代理是由一个代理的对象完成功能的方法。如果采用代理用的对象是由工厂方法创建的,可以得到一个平行结构

Java设计模式——工厂方法模式