工厂方法模式
- 1.什么是工厂方法模式
- 2.通俗的解释
- 3例子
- 3.1例子的背景。
- 3.2类的抽象
- 3.3实例类的抽象
- 3.4测试
- 3.5反思
- 4.工厂方法的扩展
- 5测试
- 6测试结果
- 7.问题
工厂方法模式或者说是简单工厂方法。
ps:学会模板方法再学习工厂方法更简单,或者说工厂方法模式是在模板方法的基础上进行设计的。
23种设计模式
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了不同的实例工厂,我们能不能抽象一个工具类,使用反射的方式来创建实例工厂,因为使用反射,那么,对于未来抽象工厂所有的子类,我们只需要使用工具类即可。(未实现,后续有机会增加)
23种设计模式