工厂方法模式
雷锋工厂
public interface IFactory {
LeiFeng CreateLeiFeng();
}
*******
public class LeiFeng {
public void sweep(){
System.out.println("扫地");
}
public void wash(){
System.out.println("洗衣服");
}
public void buyRice(){
System.out.println("买米");
}
}
*******
public class Undergraduate extends LeiFeng{
}
*******
public class UndergraduateFactory implements IFactory {
@Override
public LeiFeng CreateLeiFeng() {
return new Undergraduate();
}
}
*******
public class Volunteer extends LeiFeng{
}
******
public class VolunteerFactory implements IFactory {
@Override
public LeiFeng CreateLeiFeng() {
// TODO Auto-generated method stub
return new Volunteer();
}
}
******
public class Main {
public static void main(String[] args) {
IFactory factory1=new UndergraduateFactory();
LeiFeng student1=factory1.CreateLeiFeng();
student1.buyRice();
student1.sweep();
student1.wash();
IFactory factory2=new VolunteerFactory();
LeiFeng volunteer1=factory2.CreateLeiFeng();
volunteer1.buyRice();
volunteer1.sweep();
volunteer1.wash();
}
}
优点
- 可以在不知具体实现的情况下编程
工厂方法模式可以让你在实现功能的时候,如果需要某个产品对象,只需要使用产品的接口即可,而无需关心具体的实现。选择具体实现的任务延迟到子类去完成。 - 更容易扩展对象的新版本
工厂方法给子类提供了一个挂钩,使得扩展新的对象版本变得非常容易。比如上面示例的参数化工厂方法实现中,扩展一个新的导出Xml文件格式的实现,已有的代码都不会改变,只要新加入一个子类来提供新的工厂方法实现,然后在客户端使用这个新的子类即可。
另外这里提到的挂钩,就是我们经常说的钩子方法(hook),这个会在后面讲模板方法模式的时候详细点说明。 - 连接平行的类层次
工厂方法除了创造产品对象外,在连接平行的类层次上也大显身手。
缺点
具体产品对象和工厂方法的耦合性
在工厂方法模式里面,工厂方法是需要创建产品对象的,也就是需要选择具体的产品对象,并创建它们的实例,因此具体产品对象和工厂方法是耦合的。
本质
延迟到子类来选择实现。
应用场景
建议在如下情况中,选用工厂方法模式:
- 如果一个类需要创建某个接口的对象,但是又不知道具体的实现,这种情况可以选用工厂方法模式,把创建对象的工作延迟到子类去实现
- 如果一个类本身就希望,由它的子类来创建所需的对象的时候,应该使用工厂方法模式
相关模式
- 工厂方法模式和抽象工厂模式
这两个模式可以组合使用,具体的放到抽象工厂模式中去讲。 - 工厂方法模式和模板方法模式
这两个模式外观类似,都是有一个抽象类,然后由子类来提供一些实现,但是工厂方法模式的子类专注的是创建产品对象,而模板方法模式的子类专注的是为固定的算法骨架提供某些步骤的实现。
这两个模式可以组合使用,通常在模板方法模式里面,使用工厂方法来创建模板方法需要的对象。例题:导出数据的应用框架。导出成文本格式、数据库备份形式、Excel格式、Xml格式等 /** * 导出成文本文件格式的对象 */ public class ExportTxtFile implements ExportFileApi{ public boolean export(String data) { //简单示意一下,这里需要操作文件 System.out.println("导出数据"+data+"到文本文件"); return true; } } /** * 导出成数据库备份文件形式的对象 */ public class ExportDB implements ExportFileApi{ public boolean export(String data) { //简单示意一下,这里需要操作数据库和文件 System.out.println("导出数据"+data+"到数据库备份文件"); return true; } }/** * 实现导出数据的业务功能对象 */ public abstract class ExportOperate { /** * 导出文件 * @param data 需要保存的数据 * @return 是否成功导出文件 */ public boolean export(String data){ //使用工厂方法 ExportFileApi api = factoryMethod(); return api.export(data); } /** * 工厂方法,创建导出的文件对象的接口对象 * @return 导出的文件对象的接口对象 */ protected abstract ExportFileApi factoryMethod(); }/** * 具体的创建器实现对象,实现创建导出成文本文件格式的对象 */ public class ExportTxtFileOperate extends ExportOperate{ protected ExportFileApi factoryMethod() { //创建导出成文本文件格式的对象 return new ExportTxtFile(); } } /** * 具体的创建器实现对象,实现创建导出成数据库备份文件形式的对象 */ public class ExportDBOperate extends ExportOperate{ protected ExportFileApi factoryMethod() { //创建导出成数据库备份文件形式的对象 return new ExportDB(); } } public class Client { public static void main(String[] args) { //创建需要使用的Creator对象 ExportOperate operate = new ExportDBOperate(); //调用输出数据的功能方法 operate.export("测试数据"); } }