大话设计模式八:工厂方法模式(factory method)

一. 模式定义:

定义一个用于创建对象的接口,让子类决定实例化哪一个类,factory method使一个类的实例化延迟到其子类。


二. 结构和说明:

大话设计模式八:工厂方法模式(factory method)_第1张图片

Product:定义工厂方法所创建的对象的接口,也就是实际需要使用的对象的接口

ConcreteProduct:具体的Product接口的实现对象

Creator:创建器,声明工厂方法

ConcreteCreator:具体的创建器对象,覆盖实现Creator定义的工厂方法,返回具体的Product实例


三. 时序图:



四. 样例代码:

1. 创建器,声明工厂方法:

public abstract class Creator {
	// 创建Product的工厂方法
	protected abstract Product factoryMethod();
	
	/**
	 * 示意方法,实现某些功能的方法 
	 */
	public void someOperation() {
		// 通常在这些方法实现中,需要调用工厂方法来获取Product对象
		Product product = factoryMethod();
	}
}
2. 具体的创建器实现对象:
public class ConcreteCreator extends Creator {
	public Product factoryMethod() {
		// 重定义工厂方法,返回一个具体的Product对象
		return new ConcreteProduct();
	}
}
3. 具体的Product对象:
public class ConcreteProduct implements Product {
	// 实现Product要求的方法
}
4. 工厂方法所创建的对象的接口:
public interface Product {
	// 可以定义Product的方法
}

五. 实际案例:(不用模式)

现在我们需要实现一个导出数据的应用框架,让用户选择数据的导出方式,如:导出文本格式、导出数据库备份形式等。

现在我们采用两种实现方式:一种使用工厂方法模式,一种不使用工厂方法模式。

1. 导出的文件对象的接口:ExportFileApi

public interface ExportFileApi {
	/**
	 * 导出内容成为文件
	 * @param data 示意:需要保存的数据
	 * @return 是否导出成功
	 */
	public boolean export(String data);
}
2. 导出成文本文件格式的对象:ExportTxtFile
public class ExportTxtFile implements ExportFileApi{
	public boolean export(String data) {
		//简单示意一下,这里需要操作文件
		System.out.println("导出数据"+data+"到文本文件");
		return true;
	}
}
3. 导出成数据库备份文件形式的对象:ExportDB
public class ExportDB implements ExportFileApi{
	public boolean export(String data) {
		//简单示意一下,这里需要操作数据库和文件
		System.out.println("导出数据"+data+"到数据库备份文件");
		return true;
	}
}
4. 实现导出数据的业务功能对象:ExportOperate
public class ExportOperate {
	/**
	 * 导出文件
	 * @param type 用户选择的导出类型
	 * @param data 需要保存的数据
	 * @return 是否成功导出文件
	 */
	public boolean export(int type,String data){
		// 先完成各种导出数据前的准备工作
		System.out.println("进行数据校验");
		System.out.println("进行数据转换");
		System.out.println("进行数据格式的封装");
		
		// 然后才真正的去导出
		ExportFileApi api = null;
		
		// 根据类型来选择究竟要创建哪一种导出文件对象
		if(type == 1){
			api = new ExportTxtFile();
		}else if(type == 2){
			api = new ExportDB();
		}
		return api.export(data);
	}
}
5. 客户端:client
public class Client {
	public static void main(String[] args) {
		ExportOperate operate = new ExportOperate();
		operate.export(1, "要导出的测试数据");
	}
}

分析:我们可以看到在ExportOperate中需要判断传入的type类型来决定创建的对象,假设现在我们需要加一种导出xml的功能,那就得修改代码,再加一个判断。这显然不符合开闭原则:对添加开放,对修改关闭。

现在遇到的问题就是:对于实现导出数据的业务功能对象ExportOperate,它需要创建ExportFileApi的具体实例对象,但是它只知道ExportFileApi接口,而不知道其具体的实现,那该怎么办?


六. 实际案例:(使用模式)

1. 修改ExportOperate:

public abstract class ExportOperate {
	public ABC createABC(String name){
		return new ABC(name,factoryMethod());
	}
	
	/**
	 * 导出文件
	 * @param data 需要保存的数据
	 * @return 是否成功导出文件
	 */
	public boolean export(String data){
		// 先完成各种导出数据前的准备工作
		System.out.println("进行数据校验");
		System.out.println("进行数据转换");
		System.out.println("进行数据格式的封装");
		
		// 使用工厂方法
		ExportFileApi api = factoryMethod();
		
		// 然后才真正的去导出
		return api.export(data);
	}
	
	/**
	 * 工厂方法,创建导出的文件对象的接口对象
	 * @return 导出的文件对象的接口对象
	 */
	protected abstract ExportFileApi factoryMethod();
	
	// 抽象类:既要约束子类的行为,又要为子类提供公共的功能
}
2. 添加具体的创建器实现对象,实现创建导出成数据库备份文件形式的对象:ExportDBOperate
public class ExportDBOperate extends ExportOperate{
	protected ExportFileApi factoryMethod() {
		// 创建导出成数据库备份文件形式的对象
		return new ExportDB();
	}
}

3. 添加具体的创建器实现对象,实现创建导出成文本文件格式的对象:ExportTxtFileOperate

public class ExportTxtFileOperate extends ExportOperate{
	protected ExportFileApi factoryMethod() {
		// 创建导出成文本文件格式的对象
		return new ExportTxtFile();
	}
}

4. 客户端:client

public class Client {
	public static void main(String[] args) {
		//创建需要使用的Creator对象
		ExportOperate operate = new ExportDBOperate();
		//调用输出数据的功能方法
		operate.export("测试数据");
	}
}
ExportOperate中,因为我们并不知道究竟是创建ExportDB对象还是ExportTxtFile对象,所以我们干脆创建一个抽象的工厂方法,让子类自己去实现。

在客户端中创建的是ExportDBOperate对象,所以工厂方法创建的自然是返回ExportDB对象了。

所以工厂方法帮我们解决了在父类不知道具体实现的情况下,完成自身的功能调用,而具体的实现延迟到子类类实现。

工厂方法的实现中,通常父类会是一个抽象类,里面包含创建所需对象的抽象方法,这些抽象方法就是工厂方法。


七. Ioc和工厂方法

1. Ioc/DI对编程带来的最大变化不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在Ioc/DI思想中,应用程序就编程被动的了,被动的等待Ioc容器来创建并注入它所需要的资源了.

2. 工厂模式也是一样,我们不会主动创建ExportDB/ExportTxtFile对象,而是通过让子类实现工厂方法,让子类来创建对象。

它们的思想很类似,都是“主动变被动”,进行“主从换位”,从而获得更灵活的程序结构。小小的变动其实是编程思想的一个大进步,有效的分离了对象和它所需要的内部资源,使得阿门松散耦合,有利于功能复用。


八. 何时选用工厂方法

1. 如果一个类需要创建某个接口的对象,但是又不知道具体的实现,这种情况可以选用工厂方法模式,把创建对象的工作延迟到子类去实现。



你可能感兴趣的:(设计模式,工厂方法)