工厂方法模式
工厂方法模式(Factory method)描述
工厂方法模式是类的创建模式,又叫做虚拟构造子(Virtual Constructor)模式或者多态性工厂(Polymorphic Factory)模式。
工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
工厂方法模式场景
系统需要支持对数据库中的员工薪资进行导出,并且支持多种格式如:HTML、CSV、PDF等。每种格式导出的结构有所不同。
如果使用简单工厂模式,则工厂类必定会过于臃肿。因为简单工厂模式只有一个工厂类,他需要处理所有的创建逻辑。假如日后需求不断增加,则后果不堪设想。
这时候就需要工厂方法模式来处理以上需求。在工厂方法模式中,核心的工厂类不再负责所有的对象的创建,而是将具体创建的工作交给子类去做。这个核心类则摇身一变,成为了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个类应当被实例化的这种细节。
从上图中可看出,这个使用工厂方法模式的系统设计到以下角色:
抽象工厂(ExportFactory)角色:担任这个角色的是工厂方法模式的核心,任何在模式中创建对象的工厂类必须实现这个接口。在实际的系统中,这个角色也常常使用抽象类实现。
具体工厂(ExportHtmlFactory、ExportPdfFactory)角色:担任这个角色的是实现了抽象工厂的具体Java类。具体工厂角色含有与业务密切相关的逻辑,并且受到使用者的调用以创建导出类(如:ExportStandardHtmlFile)。
抽象导出(ExportFile)角色:工厂方法模式所创建的对象的超类,也就是所有导出类的共同父类或共同拥有的接口。在实际的系统中,这个角色也常常使用抽象类来实现。
具体导出(ExportStandardHtmlFile等)角色:这个角色实现了抽象导出(ExportFile)角色所声明的接口,工厂方法模式所创建的每一个对象都是某个具体导出角色的实例。
抽象工厂角色:
/**
* 抽象工厂
*/
public interface ExportFactory {
ExportFile factory(String type);
}
具体工厂
/**
* 具体工厂
*/
public class ExportHtmlFactory implements ExportFactory {
@Override
public ExportFile factory(String type) {
if ("standard".equals(type)) {
return new ExportStandardHtmlFile();
} else if ("financial".equals(type)) {
return new ExportFinancialHtmlFile();
} else {
throw new RuntimeException("找不到对应type");
}
}
}
public class ExportPdfFactory implements ExportFactory {
@Override
public ExportFile factory(String type) {
if ("standard".equals(type)) {
return new ExportStandardPdfFile();
} else if ("financial".equals(type)) {
return new ExportFinancialPdfFile();
} else {
throw new RuntimeException("找不到对应type");
}
}
}
抽象导出角色
/**
* 抽象导出
*/
public interface ExportFile {
boolean export(String data);
}
具体导出角色
public class ExportFinancialHtmlFile implements ExportFile {
@Override
public boolean export(String data) {
return false;
}
}
public class ExportFinancialPdfFile implements ExportFile {
@Override
public boolean export(String data) {
return false;
}
}
public class ExportStandardHtmlFile implements ExportFile {
@Override
public boolean export(String data) {
return false;
}
}
public class ExportStandardPdfFile implements ExportFile {
@Override
public boolean export(String data) {
return false;
}
}
客户端:
class Test {
public static void main(String[] args) {
String data = "";
ExportFactory exportFactory = new ExportHtmlFactory();
ExportFile ef = exportFactory.factory("financial");
ef.export(data);
}
}
工厂方法模式的活动序列图
客户端创建ExportHtmlFactory对象,这时客户端所持有变量的静态类型为ExportFactory,而实际类型为ExportHTMLFactory。然后客户端调用ExportHtmlFactory对象的工厂方法 factory(),接着后者调用ExportFinancialHtmlFile的构造器创建出导出对象。
工厂方法模式和简单工厂模式
工厂方法模式和简单工厂模式在结构上不同很明显。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
工厂方法模式退化后可以变得很像简单工厂模式。设想如果非常确定一个系统只需要一个具体工厂类,那么不妨把抽象工厂类合并到具体工厂类中去。由于只有一个具体工厂类,所以不妨将工厂方法改为静态方法,这时候就得到了简单工厂模式。
如果系统需要加入一个新的导出类型,那么所需要的就是向系统中加入一个这个导出类以及所对应的工厂类。没有必要修改客户端,也没有必要修改抽象工厂角色或者其他已有的具体工厂角色。对于增加新的导出类型而言,***这个系统完全支持“开-闭原则”***。
完结
一个系统是由多人开发的,导出的功能是你实现的,但使用者(调用这个方法的人)可能却是其他人。这时候你应该设计足够灵活并尽可能降低两者之间的耦合度,当你修改或增加一个新的功能时,使用者不需要修改任何地方。假如你的设计不够灵活,那么将无法面对客户多变的需求。可能一个极小的需求变更,都会使你的代码结构发生改变,并导致其他使用你所提供的结构的人都需要修改他们的代码。牵一发而动全身,这就使得日后这个系统将难以维护。