这两天看了大名鼎鼎的工厂模式~ headfirst的这一章挺长的,pizza的例子感觉也不是特别清楚,在网上搜了搜别人的博客又看了看,在此记录一下学习感悟吧
为什么需要工厂模式?
在Java中,创建对象的方式有多种,包括:
- 用new关键词创建,最简单常用的就是这个了
- 通过反射机制,classA.newInstance()
- Clone()方法复制
- 构造器类进行对象的创建:
Constructor c = ClassA.getConstructor(); ClassA a = c.newInstance();
这几个方法里最常见的一个就是用new关键字创建新对象,但是这样的方式违背了设计模式的原则之一——不要面向具体实现编程,而应该面对抽象、接口编程。
当我们new一个对象时,new后面跟的是一个具体的类,这样就对具体的类产生了依赖,耦合度较高。看一个例子:
public class CarStore {
public Car orderCar(String str){
Car car = null;
if (str == "BMW")
car = new BMW();
if (str == "Lexus")
car = new Lexus();
return car;
}
}
上面的CarStore类提供宝马车和雷克萨斯车,当这个类增加了奔驰车时,除了需要新增一个Benz类,还需要对CarStore类的代码对如下修改:
public class CarStore {
public Car orderCar(String str){
Car car = null;
if (str == "BMW")
car = new BMW();
if (str == "Lexus")
car = new Lexus();
if (str == "Benz")
car = new Benz();
return car;
}
}
这样的代码违背了三个原则:
- 单一职责原则,一个类既负责创建类,又负责使用类
- 开闭原则(对修改关闭,对扩展开放):对于新增的功能,需要修改旧代码,不利于维护
- 高复用原则:如果一个对象的创建比较复杂,需要多行代码,每次需要用的时候都从头到尾创建一次,重复代码多。
而工厂模式,解决的正是这样的问题。下面依次来看三种工厂模式:
1.简单工厂模式(静态工厂)
简单工厂模式,顾名思义比较简单,针对上述new关键词创建对象的弊端,简单工厂模式负责把类的创建单独封装起来,放在一个工厂类中,对于刚才的代码,简单工厂模式会这么改:
public class CarStore {
public Car orderCar(String str){
Car car = SimpleCarFactory.createCar(str);
return car;
}
}
public class SimpleCarFactory {
public SimpleCarFactory(){ }
public static Car createCar(String str){
Car car = null;
if (str == "BMW")
car = new BMW();
if (str == "Lexus")
car = new Lexus();
return car;
}
}
可以看到,车的创建工作已经被封装起来,CarStore只需要调用工厂类的createCar方法即可,不需要知道创建的细节。这样就解决了代码重复、多重职责的问题,但是一下问题还是没有得到解决:
- 依然违背开闭原则:如果要增加奔驰车,还是得修改SimpleCarFactory类的createCar方法的代码。
- SimpleCarFactory是一个具体类,仍然是在面向具体类编程。
2.工厂方法模式
为了解决上述简单工厂模式的缺点,出现了工厂方法模式:定义一个工厂抽象类,声明必要的接口,让具体的子类进行对象的创建工作。代码如下:
public class CarStore {
CarFactory carFactory;
public CarStore(CarFactory carFactory){
this.carFactory = carFactory;
}
public Car orderCar(String str){
Car car = carFactory.createCar();
return car;
}
}
public interface CarFactory {
Car createCar();
}
public class LexusCarFactory implements CarFactory {
@Override
public Car createCar() {
return new Lexus();
}
}
public class BMWCarFactory implements CarFactory{
@Override
public Car createCar(){
return new BMW();
}
}
这样一来,当需要增加奔驰车的时候,增加一个Benz类和一个BenzCarFactory类就可以了,不需要修改原有代码。而且CarStore依赖的是CarFactory接口而不是具体类。
抽象工厂模式
对于简单工厂模式而言,当车的种类越来越多后,单一工厂类的职责过重,会变得很臃肿。
而对于工厂方法模式,如果每多一种车就要新建一个工厂类+一个车类型,类的数量会快速扩张、变得越来越多不利于维护和管理。
因此,对于相互关联、依赖的类型,他们可以形成一个产品族,放到同一个工厂类中进行创建。比如车的配件工厂类,每种车的配件种类都差不多,就可以形成一个产品族。
在抽象工厂模式中,首先定义一个抽象工厂类或接口,声明需要创建的产品有哪些,由具体类对这些产品进行实现,如下:
public interface CarAccessoryFactory {
Wheel createWheel();
Window createWindow();
CarDoor createCarDoor();
}
public class BMWCarAccessoryFactory{
BMWWheel createWheel(){
return new BMWWheel();
}
BMWWheel createWindow(){
return new BMWWhindow();
}
BMWWheel createCarDoor(){
return new BMWCarDoor();
}
}
显而易见,抽象工厂模式的一个弊端就是,如果产品族发生了改变,比如车配件增加了一个底盘,这时候就需要对CarAccessoryFactory和所有实现这个接口的具体类进行更改。