一、什么是Factory Method模式
在Template Method模式中,我们在父类中规定处理的流程,在子类中实现具体的处理。如果我们将该模式用于生成实例,它就演变为本章中我们所要学习的Factory Method模式。
想先了解Template Method,可以看我的博客:设计模式学习(六):Template Method模板方法模式_玉面大蛟龙的博客
Factory有“工厂”的意思。用Template Method模式来构建生成实例的工厂,这就是Factory Method模式。
在Factory Method模式中,父类决定实例的生成方式,但并不决定所要生成的具体的类,具体的处理全部交给子类负责。这样就可以将生成实例的框架( framework )和实际负责生成实例的类解耦。
用一句话来概括:将实例的生成交给子类。
二、Factory Method示例代码
这段示例程序的作用是制作身份证(ID卡),它其中有5个类(图4-1)。
Product类和Factory类属于framework包。这两个类组成了生成实例的框架。IDCard类和 IDCardFactory类负责实际的加工处理,它们属于idCard包。Main类是用于测试程序行为的类。
之所以将他们分为不同的包,是因为如果我们想再生产其他的产品,比如创建电视机类和电视机工厂类,只需要引入framework包,只编写television包即可。
因此在阅读示例程序时,请注意所阅读的代码属于framework包还是idcard包。
2.1 类之间的关系
先看一下所有的类:
类图:
2.2 Product类
framework 包中的Product类是用来表示“产品”的类。在该类中仅声明了use抽象方法。use方法的实现则被交给了Product类的子类负责。
在这个框架中,定义了产品是“任意的可以use的”的东西。
package framework; public abstract class Product { public abstract void use(); }
2.3 Factory类
在framework包中的Factory类中,我们使用了Template Method模式。该类还声明了用于“生成产品”的createProduct抽象方法和用于“注册产品”的registerProduct抽象方法。"生成产品”和“注册产品”的具体处理则被交给了Factory类的子类负责。
在这个框架中,我们定义了工厂是用来“调用create方法生成Product实例”的。而create方法的实现是先调用createProduct生成产品,接着调用registerProduct注册产品。
具体的实现内容根据Factory Method模式适用的场景不同而不同。但是,只要是FactoryMethod模式,在生成实例时就一定会使用到Template Method模式。
在示例程序中,createProduct方法是用于生成实例的方法。不用new关键字来生成实例,而是调用生成实例的专用方法来生成实例,这样就可以防止父类与其他具体类耦合。
package framework; public abstract class Factory { public final Product create(String owner) { Product p = createProduct(owner); registerProduct(p); return p; } protected abstract void registerProduct(Product product); protected abstract Product createProduct(String owner); }
2.4 IDCard类
之前我们已经理解了框架( framework包)的代码。接下来让我们把关注点转移到负责加工处理的这一边(idcard包)。
我们先来编写表示ID卡的类,即IDCard类。为了能够明显地体现出与框架的分离,我们将这个类放在idcard包中。IDCard类是产品 Product类的子类。
需要注意的一点是:我们并没有把IDCard的构造函数声明为public类型,这是想让idcard包外的类无法new出 IDcard 类的实例。这样就可以强迫外部必须通过IDCardFactory来生成IDCard的实例(在Java中,只有同一个包中的类可以访问不带public、protected、private等修饰符的构造函数和方法)。
package idcard; public class IDCard extends Product { private String owner; IDCard(String owner) { System.out.println("制作" + owner + "的ID卡。"); this.owner = owner; } @Override public void use() { System.out.println("使用" + owner + "的ID卡。"); } public String getOwner() { return owner; } }
2.5 IDCardFactory类
package factoryMethod.idcard; public class IDCardFactory extends Factory { //IDCard的各个持有人 private List owners = new ArrayList(); //生产产品,即生成IDCard的实例 protected Product createProduct(String owner) { return new IDCard(owner); } //注册产品,即把各个产品的持有人保存到owners中 protected void registerProduct(Product product) { owners.add(((IDCard)product).getOwner()); } public List getOwners() { return owners; } }
2.6 用于测试的Main类
public class Main { public static void main(String[] args) { Factory factory = new IDCardFactory(); Product card1 = factory.create("小明"); Product card2 = factory.create("小红"); Product card3 = factory.create("小刚"); card1.use(); card2.use(); card3.use(); } }
2.7 运行结果
三、拓展思路的要点
3.1 框架与具体加工
至此,我们分别学习了“框架”与“具体加工”这两方面的内容。它们分别被封装在framework包和idcard包中。
这里,让我们用相同的框架创建出其他的“产品”和“工厂”。例如,我们这次要创建表示电视机的类Televison和表示电视机工厂的类TelevisonFactory。这时,我们只需要引入( import ) framework包就可以编写televison包。
3.2 使用模式与开发人员之间的沟通
不论是我们在之前学习的Template Method模式还是本文中学习的Factory Method模式,在实际工作中使用时,都会让我们感觉到比较困难。这是因为,如果仅阅读一个类的代码,是很难理解这个类的行为的。必须要理解父类中所定义的处理的框架和它里面所使用的抽象方法,然后阅读代码,了解这些抽象方法在子类中的实现才行。
通常,使用设计模式设计类时,必须要向维护这些类的开发人员正确地传达设计这些设计模式的意图。否则,维护人员在修改设计时可能会违背设计者最初的意图。
这时,我们建议在程序注释中和开发文档中记录所使用的设计模式的名称和意图。
四、相关的设计模式
4.1 Template Method模式
Factory Method模式是Template Method的典型应用。在示例程序中,create方法就是模板方法。
设计模式学习(六):Template Method模板方法模式_玉面大蛟龙的博客-CSDN博客
4.2 Singleton模式
在多数情况下我们都可以将Singleton模式用于扮演Creator角色(或是ConcreteCreator角色)的类。这是因为在程序中没有必要存在多个Creator角色(或是ConcreteCreator角色)的实例。不过在示例程序中,我们并没有使用Singleton模式。
4.3 Composite模式
有时可以将Composite模式用于Product角色(或是ConcreteProduct角色 )。
4.4 lterator模式
有时,在 Iterator模式中使用iterator方法生成Iterator的实例时会使用Factory Method模式。