创建型模式——工厂模式
我们在实例化对象时,一般都是通过类的构造函数来实例化的,比如:
// Car继承自Vehicle
Vehicle vehicle = new Car();
这段代码说明了Vehicle和Car两个类之间的依赖关系。这样的依赖关系使代码紧密耦合,在不更改的情况下很难扩展。举例来说,假设要用Truck
替换Car
,就需要修改相应的代码:
// Car继承自Vehicle
Vehicle vehicle = new Truck();
这里存在两个问题:其一,类应该保持对扩展的开放和对修改的关闭(开闭原则);其二,每个类应该只有一个发生变化的原因(单一职责原则)。每增加新的类造成主要代码修改时会打破开闭原则,而主类除了其固有功能之外还负责实例化vehicle
对象,这种行为将会打破单一职责原则。
在这种情况下就需要一种更好的设计方案。我们可以增加一个新类来负责实例化vehicle
对象,称之为简单工厂模式。
简单工厂模式
工厂模式用于实现逻辑的封装,并通过公共的接口提供对象的实例化服务,在添加新的类时只需要做少量的修改。
类SimpleFactory
中包含实例化ConcreteProduct1
和ConcreteProduct2
的代码。当客户需要对象时,调用SimpleFactory
的createProduct()
方法,并提供参数指明所需对象的类型。SimpleFactory
实例化相应的具体产品并返回,返回的产品对象被转换为基类类型。因此,无论是ConcreteProduct1
还是ConcreteProduct2
,客户能以相同的方式处理。
1. 静态工厂模式
下面我们写一个简单的工厂类用来创建Vehicle实例。我们创建一个抽象Vehicle类和继承自它的三个具体类:Bike
、Car
和Truck
。工厂类(也叫静态工厂类)代码如下所示:
/**
* @author: Jay Mitter
* @date: 2020-08-12 21:26
* @description: 静态工厂模式
* 1.抽象类要被子类继承,接口要被类实现。
* 2.接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。
* 3.接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
* 4.接口是设计的结果,抽象类是重构的结果。
* 5.抽象类和接口都是用来抽象具体对象,但是接口的抽象级别最高。
* 6.抽象类可以有具体的方法和属性,接口只能有抽象方法和不可变常量。
* 7.抽象类主要用来抽象类别,接口主要用来抽象功能。
*/
public class VehicleFactory {
public enum VehicleType {
Bike, Car, Truck;
}
public static AbstractVehicle create(VehicleType type) {
if (type.equals(VehicleType.Bike)) {
return new Bike();
}
if (type.equals(VehicleType.Car)) {
return new Car();
}
if (type.equals(VehicleType.Truck)) {
return new Truck();
}
return null;
}
}
工厂类逻辑非常简单,只负责Vehicle
类的实例化,符合单一职责原则;用户只调用Vehicle
接口,这样做可以减少耦合,符合依赖倒置原则;但是当增加一个新的Vehicle
类时,需要对VehicleFactory
类进行修改,这样就打破了开闭原则。
我们可以改进这种简单工厂模式,使得注册的新类在使用时才被实例化,从而保证其对扩展开放,同时对修改闭合。
具体的实现方式有以下两种:
- 使用反射机制注册产品类对象和实例化。
- 注册产品对象并向每个产品添加
newInstance
方法,该方法返回与自身类型相同的新实例。
2. 使用反射机制进行类注册的简单工厂模式
/**
* @author: Jay Mitter
* @date: 2020-08-12 21:26
* @description: 静态工厂模式
* 1.抽象类要被子类继承,接口要被类实现。
* 2.接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。
* 3.接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
* 4.接口是设计的结果,抽象类是重构的结果。
* 5.抽象类和接口都是用来抽象具体对象,但是接口的抽象级别最高。
* 6.抽象类可以有具体的方法和属性,接口只能有抽象方法和不可变常量。
* 7.抽象类主要用来抽象类别,接口主要用来抽象功能。
*/
public class VehicleFactory {
public enum VehicleType {
Bike, Car, Truck;
}
/**
* 使用map对象来保存产品ID极其对应的类
*/
private Map<String, Class> registeredProducts = new HashMap<>();
/**
* 注册新Vehicle类的方法
* @param vehicleId id
* @param vehicleClass 类全类路径
*/
public void registerVehicle(String vehicleId, Class vehicleClass) {
registeredProducts.put(vehicleId, vehicleClass);
}
/**
* 构造方法,根据注册的对象获取对应的类
* @param type 对应vehicleId
* @return
* @throws IllegalAccessException
* @throws InstantiationException
*/
public AbstractVehicle createVehicle(String type) throws IllegalAccessException, InstantiationException {
Class productClass = registeredProducts.get(type);
return (AbstractVehicle) productClass.newInstance();
}
public static AbstractVehicle create(VehicleType type) {
if (type.equals(VehicleType.Bike)) {
return new Bike();
}
if (type.equals(VehicleType.Car)) {
return new Car();
}
if (type.equals(VehicleType.Truck)) {
return new Truck();
}
return null;
}
}
测试:
/**
* 简单工厂模式测试
*/
@Test
public void testFactoryPattern() {
// 静态方法创建对象,根据已经写死的VehicleType创建对象
AbstractVehicle abstractVehicle = VehicleFactory.create(VehicleFactory.VehicleType.Car);
assert abstractVehicle != null;
abstractVehicle.doSomething();
// 注册的新类在使用时才被实例化
VehicleFactory vehicleFactory = new VehicleFactory();
try {
// 先注册
vehicleFactory.registerVehicle("car", com.pengjs.book.review.designpattern.factory.Car.class);
// 再创建对象实例
AbstractVehicle car = vehicleFactory.createVehicle("car");
car.doSomething();
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
但在某些情况下,反射机制并不适用。比如,反射机制需要运行时权限,这在某些特定环境中是无法实现的。反射机制也会降低程序的运行效率,在对性能要求很高的场景下应该避免使用这种机制。
3. 使用newInstance方法进行类注册的简单工厂模式
image.png/**
* @author: Jay Mitter
* @date: 2020-08-12 21:26
* @description: 静态工厂模式
* 1.抽象类要被子类继承,接口要被类实现。
* 2.接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。
* 3.接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
* 4.接口是设计的结果,抽象类是重构的结果。
* 5.抽象类和接口都是用来抽象具体对象,但是接口的抽象级别最高。
* 6.抽象类可以有具体的方法和属性,接口只能有抽象方法和不可变常量。
* 7.抽象类主要用来抽象类别,接口主要用来抽象功能。
*/
public class VehicleFactory {
public enum VehicleType {
Bike, Car, Truck;
}
/**
* 使用map对象来保存产品ID及其对应的类
*/
private Map<String, Class> registeredProducts = new HashMap<>();
/**
* 使用map对象来保存产品ID极其对应的抽象类
*/
private Map<String, AbstractVehicle> registeredVehicles = new HashMap<>();
/**
* 注册新Vehicle类的方法
* @param vehicleId id
* @param vehicleClass 类全类路径
*/
public void registerVehicle(String vehicleId, Class vehicleClass) {
registeredProducts.put(vehicleId, vehicleClass);
}
/**
* 注册子类,使用具体的实现类vehicle,避免了使用反射
* @param vehicleId id
* @param vehicle 具体的子类:Car Bike Truck等
*/
public void registerVehicleBySub(String vehicleId, AbstractVehicle vehicle) {
registeredVehicles.put(vehicleId, vehicle);
}
/**
* 构造方法,根据注册的对象获取对应的类
* @param type 对应vehicleId
* @return
* @throws IllegalAccessException
* @throws InstantiationException
*/
public AbstractVehicle createVehicle(String type) throws IllegalAccessException, InstantiationException {
Class productClass = registeredProducts.get(type);
return (AbstractVehicle) productClass.newInstance();
}
/**
* 使用每个子类的newInstance创建对象(实例),避免了使用反射的性能消耗
* @param vehicleId
* @return
* @throws IllegalAccessException
* @throws InstantiationException
*/
public AbstractVehicle createVehicleByIdSub(String vehicleId) throws IllegalAccessException, InstantiationException {
// 每个子类都实现了抽象类的newInstance方法
return (AbstractVehicle) registeredProducts.get(vehicleId).newInstance();
}
public static AbstractVehicle create(VehicleType type) {
if (type.equals(VehicleType.Bike)) {
return new Bike();
}
if (type.equals(VehicleType.Car)) {
return new Car();
}
if (type.equals(VehicleType.Truck)) {
return new Truck();
}
return null;
}
}
测试:
/**
* 简单工厂模式测试
*/
@Test
public void testFactoryPattern() {
// 静态方法创建对象,根据已经写死的VehicleType创建对象
AbstractVehicle abstractVehicle = VehicleFactory.create(VehicleFactory.VehicleType.Car);
assert abstractVehicle != null;
abstractVehicle.doSomething();
// 注册的新类在使用时才被实例化
VehicleFactory vehicleFactory = new VehicleFactory();
try {
// 先注册
vehicleFactory.registerVehicle("car", com.pengjs.book.review.designpattern.factory.Car.class);
// 再创建对象实例
AbstractVehicle car = vehicleFactory.createVehicle("car");
car.doSomething();
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
// 注册
vehicleFactory.registerVehicleBySub("car", new com.pengjs.book.review.designpattern.factory.Car());
try {
AbstractVehicle car = vehicleFactory.createVehicleByIdSub("car");
car.doSomething();
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
工厂方法模式
工厂方法模式是在静态工厂模式上的改进。工厂类被抽象化,用于实例化特定产品类的代码被转移到实现抽象方法的子类中。这样不需要修改就可以扩展工厂类。
假设有一个汽车工厂,目前只生产两种车型,小型跑车和大型家用车。在软件中,顾客可以自由决定买小型车或大型车。首先,我们需要创建一个Vehicle类和两个子类,子类分别为
SportCar
和SedanCar
。工厂类中并不包含任何创建新实例的代码,各个子类工厂实现该方法创建子类实例:
/**
* @author: Jay Mitter
* @date: 2020-08-15 08:56
* @description:
*/
public abstract class AbstractVehicleFactory {
/**
* 抽象方法创建Vehicle实例,各个子类实现该方法创建子类实例
* @param size
* @return
*/
protected abstract Vehicle createVehicle(String size);
public Vehicle orderVehicle(String size, String name) {
Vehicle vehicle = createVehicle(size);
vehicle.setName(name);
return vehicle;
}
}
Car
类工厂,创建SportCar
和SedanCar
:
/**
* @author: Jay Mitter
* @date: 2020-08-15 09:03
* @description: Car类工厂,创建SportCar和SedanCar
*/
public class CarFactory extends AbstractVehicleFactory {
@Override
protected Vehicle createVehicle(String size) {
if ("small".equals(size)) {
return new SportCar("sport");
} else if ("large".equals(size)) {
return new SedanCar("sedan");
}
return null;
}
}
此时,我们意识到汽车工厂所带来的收益,是时候进一步拓展业务了。市场调查显示卡车的需求量很大,因此我们建一个卡车工厂(TruckFactory
):
/**
* @author: Jay Mitter
* @date: 2020-08-15 09:03
* @description:
*/
public class TruckFactory extends AbstractVehicleFactory {
@Override
protected Vehicle createVehicle(String size) {
if ("small".equals(size)) {
return new SmallTruck("small truck");
} else if ("large".equals(size)) {
return new LargeTruck("large truck");
}
return null;
}
}
匿名具体工厂模式
/**
* 简单工厂模式测试2
*/
@Test
public void testFactoryPattern2() {
// Car类工厂
AbstractVehicleFactory carFactory = new CarFactory();
SedanCar sedanCar = (SedanCar) carFactory.orderVehicle("large", "car");
System.out.println(JSON.toJSONString(sedanCar));
// Truck类工厂
AbstractVehicleFactory truckFactory = new TruckFactory();
LargeTruck largeTruck = (LargeTruck) truckFactory.orderVehicle("large", "large truck");
System.out.println(JSON.toJSONString(largeTruck));
// Truck类工厂,直接创建匿名类来对AbstractVehicleFactory扩展即可
AbstractVehicleFactory bikeFactory = new AbstractVehicleFactory() {
@Override
protected Vehicle createVehicle(String size) {
if ("small".equals(size)) {
return new MountainBike("mountain bike");
} else if ("large".equals(size)) {
return new CityBike("city bike");
}
return null;
}
};
MountainBike mountainBike = (MountainBike) bikeFactory.orderVehicle("small", "mountain bike");
System.out.println(JSON.toJSONString(mountainBike));
}
实体类:
/**
* @author: Jay Mitter
* @date: 2020-08-15 09:05
* @description:
*/
public class SedanCar extends Vehicle {
public SedanCar(String name) {
super(name);
}
}
/**
* @author: Jay Mitter
* @date: 2020-08-15 09:05
* @description:
*/
public class SportCar extends Vehicle {
public SportCar(String name) {
super(name);
}
}
/**
* @author: Jay Mitter
* @date: 2020-08-15 09:19
* @description:
*/
public class SmallTruck extends Vehicle {
public SmallTruck(String name) {
super(name);
}
}
/**
* @author: Jay Mitter
* @date: 2020-08-15 09:20
* @description:
*/
public class LargeTruck extends Vehicle {
public LargeTruck(String name) {
super(name);
}
}
/**
* @author: Jay Mitter
* @date: 2020-08-15 09:19
* @description:
*/
public class SmallTruck extends Vehicle {
public SmallTruck(String name) {
super(name);
}
}
/**
* @author: Jay Mitter
* @date: 2020-08-15 09:25
* @description:
*/
public class MountainBike extends Vehicle {
public MountainBike(String name) {
super(name);
}
}
/**
* @author: Jay Mitter
* @date: 2020-08-15 09:26
* @description:
*/
public class CityBike extends Vehicle {
public CityBike(String name) {
super(name);
}
}
抽象工厂模式
抽象工厂模式是工厂方法模式的扩展版本。它不再是创建单一类型的对象,而是创建一系列相关联的对象。如果说工厂方法模式中只包含一个抽象产品类,那么抽象工厂模式则包含多个抽象产品类。
工厂方法类中只有一个抽象方法,在不同的具体工厂类中分别实现抽象产品的实例化,而抽象工厂类中,每个抽象产品都有一个实例化方法。
如果我们采用抽象工厂模式并将它应用于包含单个对象的簇,那么就得到了工厂方法模式。工厂方法模式只是抽象工厂模式的一种特例。
抽象工厂模式由以下类组成:
- AbstractFactory(抽象工厂类):抽象类,用于声明创建不同类型产品的方法。它针对不同的抽象产品类都有对应的创建方法。
- ConcreteFactory(具体工厂类):具体类,用于实现抽象工厂基类中声明的方法。针对每个系列的产品都有一个对应的具体工厂类。
-
AbstracProduct(抽象产品类):对象所需的基本接口或类。一簇相关的产品类由来自不同层级的相似产品类组成。
ProductA1
和ProductB1
来自第一个类簇,由ConcreteFactory1
实例化。ProductA2
和ProductB2
来自第二个类簇,由ConcreteFactory2
实例化。