23种设计模式----工厂方法模式----创建型模式

版权声明:本文为博主原创文章,转载请注明作者。 https://blog.csdn.net/a18792721831/article/details/83152714


工厂方法模式或者说是简单工厂方法。
ps:学会模板方法再学习工厂方法更简单,或者说工厂方法模式是在模板方法的基础上进行设计的。

1.什么是工厂方法模式

将实例的生成交给子类(出自《图解设计模式》)
这句话怎么理解?
我自己的理解就是把创建和实现分离。
使用工厂方法,抽象的工厂决定怎么创建实例,而具体的实例的创建由抽象的工厂的实现去完成。
同样的的,需要被工厂创建的类也可以抽象为抽象类,抽象类说明这些需要被创建的类的共性,而具体创建的类则是根据需要的抽象类的子类。
很难理解
很难理解
很难理解

2.通俗的解释

首先建立一个概念:
抽象工厂:决定怎么创建实例的抽象工厂类
实例工厂:具体执行创建的实例工厂类
抽象产品:需要被创建的类的抽象类共性类
实例产品:真正意义上被创建的类
所以呢,抽象工厂就是使用模板方法的思想。
由抽象的工厂定义创建的方式—关联抽象产品(模板类)
而实例的工厂实际创建----关联实例产品(实现类)
所以,这里又能够和模板方法对应。

3例子

3.1例子的背景。

车,大家都不陌生。车有自己的属性,同时每一种车需要有自己的交通规则需要遵守,比如自行车和小汽车,机动车和非机动车。。。。
造车厂,虽然没有真正的参观过,但是都听说过,造车厂里面的每一种车的建造方式又不相同,有三轮车,小汽车,大巴车。。。。

3.2类的抽象

为了显示方法的调用先后顺序等等,创建一个方法类,但是为了增加难度,我们不是使用静态方法的方式,而是使用继承的方式:

public class Show {

	public static void show(boolean b,String name){
		System.out.print("#####################################");
		System.out.print(name + (b?"开始":"结束"));
		System.out.println("######################################");
	}
	
}

根据背景。所有的车有一定的共性:一些基本的属性和需要遵守的交通规则,所以,可以得到车的抽象类

/**
 * 定义车有类型和宽和高三个属性
 * 定义车的实例创建后,车的属性无法修改
 * 定义所有的车必须遵守交通规则
 * 设置,默认属性的全参构造
 */
public abstract class Car extends Show{
	
	private String type;
	
	private Double width;
	
	private Double height;
	
	public Car(String type,Double width,Double height){
		this.type = type;
		this.width = width;
		this.height = height;
	}
	
	public abstract void trafficRuler();

	public String getType() {
		return type;
	}

	public Double getWidth() {
		return width;
	}

	public Double getHeight() {
		return height;
	}
	
}

有了抽象的车,那么抽象的造车厂也就必须有:

/**
 * 定义一个车的工厂
 * 定义创建车的三个步骤:
 * --doType
 * --doWidth
 * --doHeight
 * 给车定义一个默认的交通规则:靠右行
 */
public abstract class Factory extends Show{
	
	protected abstract void doType();
	
	protected abstract void doWidth();
	
	protected abstract void doHeight();
	
	private Car car;
	
	public Car create(String type,Double width,Double height){
		super.show(true, "Factory#create");
		car = getCar(type,width,height);
		doType();
		doWidth();
		doHeight();
		super.show(false, "Factory#create");
		return car;
	}
	protected abstract Car getCar(String type,Double width,Double height);
}

稍微总结一下。
抽象产品和抽象工厂都有了
在抽象工厂中关联了抽象产品,需要特别理解的就是为什么工厂方法是模板方法的基础上设计的。
在抽象工厂中,使用了一个抽象的方法getCar,这个抽象的方法是在抽象工厂的子类中进行实现的,所以,这里是一个模板方法的使用。

3.3实例类的抽象

有了抽象的产品和抽象的工厂,接下来就是根据需要,实现实例的工厂个实例的产品。
假设我们需要的车是宝马车,工厂是宝马的工厂:

public class BMWCar extends Car{

	public BMWCar(String type, Double width, Double height) {
		super(type, width, height);
	}
	@Override
	public void trafficRuler() {
		super.show(true, "BMWCar#trafficRuler");
		System.out.println("BMWCar#traffic");
		super.show(false, "BMWCar#trafficRuler");
	}

}

宝马车有自己的三个基本属性之外,还有自己的交通规则,比如宝马车只能在公路上行驶,不能再人行道上行驶,不能上天桥。。。。
宝马车的实例工厂:

public class BMWFactory extends Factory{
	
	private BMWCar bmwCar;
	
	public BMWCar create(String type,Double width,Double height,String carName){
		super.show(true, "Factory#create");
		bmwCar = (BMWCar) getCar(type,width,height);
		doType();
		doWidth();
		doHeight();
		super.show(false, "Factory#create");
		return bmwCar;
	}
	
	
	
	@Override
	protected void doType() {
		super.show(true, "BMWFactory#doType");
		System.out.println("BMW#doType");
		super.show(false, "BMWFactory#doType");
	}

	@Override
	protected void doWidth() {
		super.show(true, "BMWFactory#doWidth");
		System.out.println("BMW#doWidth");
		super.show(false, "BMWFactory#doWidth");
	}

	@Override
	protected void doHeight() {
		super.show(true, "BMWFactory#doHeight");
		System.out.println("BMW#doHeight");
		super.show(false, "BMWFactory#doHeight");
	}
	
	
	@Override
	protected Car getCar(String type,Double width,Double height) {
		return new BMWCar(type,width,height);
	}

}

实例工厂中实现了我们抽象工厂中的getCar的抽象方法,这里就是模板方法的实现类
同样呢,可以这么理解:
抽象工厂创建的是抽象产品
实例工厂创建的是实例产品
抽象和实例是完全分离的
没有实例,抽象部分也不会报错,但是不能使用,因为有抽象方法未实现(除非使用内部类的方式实现抽象方法)
实例部分,操作的都是实例相关的变量,和抽象部分没有关系。实现抽象和实例分离。

3.4测试

具体怎么使用呢?

public class Main {

	public static void main(String[] args) {

		Factory factory = new BMWFactory();
		BMWCar car = (BMWCar)factory.create("SUV", 2.3, 1.7);
		car.trafficRuler();
	}

}

我们首先需要一个实例工厂,然后传入参数创建一个实例对象:
所以,首先获得一个实例的工厂,接下来,创建一个实例对象。
输出结果:

#####################################Factory#create开始######################################
#####################################BMWFactory#doType开始######################################
BMW#doType
#####################################BMWFactory#doType结束######################################
#####################################BMWFactory#doWidth开始######################################
BMW#doWidth
#####################################BMWFactory#doWidth结束######################################
#####################################BMWFactory#doHeight开始######################################
BMW#doHeight
#####################################BMWFactory#doHeight结束######################################
#####################################Factory#create结束######################################
#####################################BMWCar#trafficRuler开始######################################
BMWCar#traffic
#####################################BMWCar#trafficRuler结束######################################

3.5反思

发现这样还是没有什么变化,甚至复杂化了问题,比如,我们的工厂方法中同样使用了new的关键字,虽然不是直接new一个BMW的对象,但是new了一个BMW的工厂,然后通过工厂来创建的对象。
首先,这样做有一个好处:模板方法的好处,我们可以在工厂做一些除了创建实例之外的操作,比如对创建的实例进行初始化操作之类的。
第二,我们可以先行定义产品如何创建----模板方法。

4.工厂方法的扩展

为什么使用工厂方法,就是为了更好的扩展,使用更加分离的代码。
接下来我们的需求是自行车。
首先创建自行车的实例产品:

public class Bike extends Car{

	public Bike(String type, Double width, Double height) {
		super(type, width, height);
	}

	@Override
	public void trafficRuler() {
		super.show(true, "Bike#trafficRuler");
		System.out.println("Bike#traffic");
		super.show(false, "Bike#trafficRuler");
	}

}

接下来是自行车的实例工厂:

public class BikeFactory extends Factory{

	private Bike bike;
	
	public Bike create(String type,Double width,Double height,String carName){
		super.show(true, "Factory#create");
		bike = (Bike) getCar(type,width,height);
		doType();
		doWidth();
		doHeight();
		super.show(false, "Factory#create");
		return bike;
	}
	
	@Override
	protected void doType() {
		super.show(true, "BikeFactory#doType");
		System.out.println("BikeFactory#doType");
		super.show(false, "BikeFactory#doType");
	}

	@Override
	protected void doWidth() {
		super.show(true, "BikeFactory#doWidth");
		System.out.println("BikeFactory#doWidth");
		super.show(false, "BikeFactory#doWidth");
	}

	@Override
	protected void doHeight() {
		super.show(true, "BikeFactory#doHeight");
		System.out.println("BikeFactory#doHeight");
		super.show(false, "BikeFactory#doHeight");
	}

	@Override
	protected Car getCar(String type, Double width, Double height) {
		return new Bike(type, width, height);
	}

}

5测试

测试只需要在之前的测试方法中添加:

//自行车
		factory = new BikeFactory();
		Bike bike = (Bike)factory.create("凤凰", 0.2, 1.3);
		bike.trafficRuler();

6测试结果

#####################################Factory#create开始######################################
#####################################BMWFactory#doType开始######################################
BMW#doType
#####################################BMWFactory#doType结束######################################
#####################################BMWFactory#doWidth开始######################################
BMW#doWidth
#####################################BMWFactory#doWidth结束######################################
#####################################BMWFactory#doHeight开始######################################
BMW#doHeight
#####################################BMWFactory#doHeight结束######################################
#####################################Factory#create结束######################################
#####################################BMWCar#trafficRuler开始######################################
BMWCar#traffic
#####################################BMWCar#trafficRuler结束######################################
#####################################Factory#create开始######################################
#####################################BikeFactory#doType开始######################################
BikeFactory#doType
#####################################BikeFactory#doType结束######################################
#####################################BikeFactory#doWidth开始######################################
BikeFactory#doWidth
#####################################BikeFactory#doWidth结束######################################
#####################################BikeFactory#doHeight开始######################################
BikeFactory#doHeight
#####################################BikeFactory#doHeight结束######################################
#####################################Factory#create结束######################################
#####################################Bike#trafficRuler开始######################################
Bike#traffic
#####################################Bike#trafficRuler结束######################################

7.问题

进一步反思,发现这样做还是有问题:
在测试方法中,我们new了不同的实例工厂,我们能不能抽象一个工具类,使用反射的方式来创建实例工厂,因为使用反射,那么,对于未来抽象工厂所有的子类,我们只需要使用工具类即可。(未实现,后续有机会增加)

猜你喜欢

转载自blog.csdn.net/a18792721831/article/details/83152714