目录
场景描叙:
1、简单工厂模式
1.1、静态工厂模式
1.2、 使用反射机制进行类注册的简单工厂模式
1.3、使用 newInstance 方法进行类注册的简单工厂模式
2、工厂方法模式
2.1、案例场景:假设有一个汽车工厂,目前只生产两种车型,小型跑车和大型家用车。顾客决定买小还是大型。
2.2、这时候,我们需要拓展业务,增加卡车类的生产,那我们可以创建一个卡车工厂(TruckFactory)。
3、抽象工厂模式
结尾:
场景描叙:
比如小汽车(Car)和 卡车 (Truck)都属于车辆(Vehicle),那我们实例化对象时,就需要分别实例化两个对象。
Vehicle vehicle = new Car();
Vehicle vehicle = new Truck();
以上的代码就存在两个问题:
1)类应该保持对扩展开放,对修改关闭(开闭原则);
每增加新的类造成主要代码修改会打破开闭原则。
2)每个类应该只有一个发生变化的原因(单一职责原则);
而主类除了自身固有功能还要负责实例化 vehicle 对象,这种行为打破了单一职责原则。
所以这种情况下就需要一种更好的设计方案。我们可以增加一个新类来负责实例化 vehicle 对象,称之为简单工厂模式。
1、简单工厂模式
工厂模式用于实现逻辑的封装,并通过公共接口提供对象的实例化服务,在添加新类时只需要做少量修改即可。
通俗点儿就是封装一个抽象工厂类,实现对象的实例化。
简单工厂的实现描叙如 图 1-1 所示:
图 1-1
1.1、静态工厂模式
我们创建一个抽象 Vehicle 类和继承自它的三个具体类:Bike、Car 和 Truck
代码语言:javascript复制package com.zhaoyanfei.designpattern.simpleFactory;
public abstract class Vehicle {
}
代码语言:javascript复制package com.zhaoyanfei.designpattern.simpleFactory;
public class Bike extends Vehicle {
}
代码语言:javascript复制package com.zhaoyanfei.designpattern.simpleFactory;
public class Car extends Vehicle {
}
代码语言:javascript复制package com.zhaoyanfei.designpattern.simpleFactory;
public class Truck extends Vehicle {
}
这里,我们写一个简单的工厂类用来创建 Vehicle 实例。工厂类(静态工厂类)代码如下:
代码语言:javascript复制package com.zhaoyanfei.designpattern.simpleFactory;
public class VehicleFactory {
public enum VehicleType
{
Bike,Car,Truck;
}
public static Vehicle 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();
else return null;
}
}
通过上面代码示例,我们可以看到工厂类逻辑非常简单,只负责抽象类 (Vehicle) 类的实例化,符合单一职责原则,用户只需要调用 Vehicle 接口,这么做可以减少耦合,符合依赖倒置原则;但是增加一个新的 Vehicle 类时,需要对 VehicleFactory 工厂类进行修改,就打破了开闭原则。
我们可以改进这种简单工厂模式,使得注册的新类在使用时才被实例化,从而保证其对扩展开放,对修改关闭。
具体实现方式有以下两种:
1)使用反射机制注册产品类对象和实例化。
2)注册产品对象并向每个产品添加 newInstanse 方法,该方法返回与自身类型相同的新实例。
1.2、 使用反射机制进行类注册的简单工厂模式
这里,我们在工厂类中需要用 map 对象来保存产品 ID 及其对应的类:
然后增加一个注册新 Vehicle 类的方法
代码语言:javascript复制package com.zhaoyanfei.designpattern.simpleFactory;
import java.util.HashMap;
import java.util.Map;
public class VehicleFactory {
public enum VehicleType
{
Bike,Car,Truck;
}
public static Vehicle 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();
else return null;
}
//工厂类中需要用 map 对象来保存产品 ID 及其对应的类
private Map<String,Class> registeredProducts = new HashMap<String,Class>();
//然后增加一个注册新 Vehicle 类的方法
public void registerVehicle(String vehicleId,Class vehicelClass) {
registeredProducts.put(vehicleId, vehicelClass);
}
//构造方法如下所示:
public Vehicle createVehicle(String type) throws InstantiationException, IllegalAccessException {
Class productClass = registeredProducts.get(type);
return (Vehicle) productClass.newInstance();
}
}
上面代码中,我们可以看到反射实例化对象时,会有异常抛出。所以在某些情况下,反射机制并不适用。另外,反射机制也会降低程序的运行效率,在对性能要求很高的场景下应该避免使用这种机制。
1.3、使用 newInstance 方法进行类注册的简单工厂模式
前面我们用的反射机制来实现新 Vehicle 类的实例化。如果要避免使用反射机制,可以使用注册新 Vehicle 类的类似工厂类,不再将类添加到 map 对象中,而是将要注册的每种对象实例添加其中。每个产品类都能够创建自己的实例。
1)首先在基类 Vehicle 中添加一个抽象方法:
代码语言:javascript复制package com.zhaoyanfei.designpattern.simpleFactory;
public abstract class Vehicle {
abstract public Vehicle newInstance();
}
2)此时,大家都知道,子类必须实现基类中声明的抽象方法:
Bike、Car 和 Truck 都需要实现 newInstance()方法,每个产品类创建自己的实例。
代码语言:javascript复制package com.zhaoyanfei.designpattern.simpleFactory;
public class Bike extends Vehicle {
@Override
public Vehicle newInstance() {
return new Bike();
}
}
3)在工厂类中,更改 map 用于保存对象的 ID 及其对应的 Vehicle 对象:
代码语言:javascript复制package com.zhaoyanfei.designpattern.simpleFactory;
import java.util.HashMap;
import java.util.Map;
public class VehicleFactory {
public enum VehicleType
{
Bike,Car,Truck;
}
public static Vehicle 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();
else return null;
}
/**
* 反射机制
*/
//工厂类中需要用 map 对象来保存产品 ID 及其对应的类
// private Map<String,Class> registeredProducts = new HashMap<String,Class>();
// //然后增加一个注册新 Vehicle 类的方法
// public void registerVehicle(String vehicleId,Class vehicelClass) {
// registeredProducts.put(vehicleId, vehicelClass);
// }
// //构造方法如下所示:
// public Vehicle createVehicle(String type) throws InstantiationException, IllegalAccessException {
// Class productClass = registeredProducts.get(type);
// return (Vehicle) productClass.newInstance();
// }
/**
* 注册产品对象,并向每个产品添加 newInstance 方法,该方法返回与自身类型相同的新实例
*/
private Map<String,Vehicle> registeredProducts = new HashMap<String,Vehicle>();
//然后增加一个注册新 Vehicle 类的方法
public void registerVehicle(String vehicleId,Vehicle vehicle) {
registeredProducts.put(vehicleId, vehicle);
}
//构造方法如下所示:
public Vehicle createVehicle(String type) {
Vehicle productClass = registeredProducts.get(type);
return productClass.newInstance();
}
}
2、工厂方法模式
工厂方法模式(FACTORY METHOD)是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂;具体工厂;抽象产品;具体产品
工厂方法模式是在静态工厂模式上的改进。工厂类被抽象化,用于实例化特定产品类的代码被转移到实现抽象方法的子类中。这样就不需要修改就可以扩展工厂类。实现如 图2-1:
图2-1
2.1、案例场景:假设有一个汽车工厂,目前只生产两种车型,小型跑车和大型家用车。顾客决定买小还是大型。
1)首先我们需要创建一个 Vehicle 类和两个子类,子类分别为 SportCar 和 SedanCar。
代码语言:javascript复制package com.zhaoyanfei.designpattern.factorymethod;
public class Vehicle {
String color;
public void setColor(String color) {
this.color = color;
}
}
代码语言:javascript复制package com.zhaoyanfei.designpattern.factorymethod;
public class SportCar extends Vehicle {
}
代码语言:javascript复制package com.zhaoyanfei.designpattern.factorymethod;
public class SedanCar extends Vehicle {
}
2)创建抽象工厂类,此类中不包含任何创建新实例的代码:
代码语言:javascript复制package com.zhaoyanfei.designpattern.factorymethod;
public abstract class VehicleFactory {
protected abstract Vehicle createVehicle(String item);
public Vehicle orderVehicle(String size,String color) {
Vehicle vehicle = createVehicle(size);
vehicle.setColor(color);
return vehicle;
}
}
3)增加汽车实例化代码,我们创建 VehicleFactory 的子类
代码语言:javascript复制package com.zhaoyanfei.designpattern.factorymethod;
public class CarFactory extends VehicleFactory {
@Override
protected Vehicle createVehicle(String size) {
if(size.equals("small")) {
return new SportCar();
}else if(size.equals("large")) {
return new SedanCar();
}else {
return null;
}
}
}
4)客户端,我们只需要创建工厂类并创建订单:
代码语言:javascript复制package com.zhaoyanfei.designpattern.factorymethod;
public class TestMethodFactory {
public static void main(String[] args) {
VehicleFactory carFactory = new CarFactory();
Vehicle orderVehicle = carFactory.orderVehicle("large", "green");
System.out.println("类名:" orderVehicle.getClass().getName() "颜色:" orderVehicle.color);
}
}
运行后可以看到如下输出:
2.2、这时候,我们需要拓展业务,增加卡车类的生产,那我们可以创建一个卡车工厂(TruckFactory)。
代码语言:javascript复制package com.zhaoyanfei.designpattern.factorymethod;
public class TruckFactory extends VehicleFactory {
@Override
protected Vehicle createVehicle(String size) {
if(size.equals("small")) {
return new SmallTruck();
}else if(size.equals("large")) {
return new LargeTruck();
}else {
return null;
}
}
}
我们就可以这样来创建卡车订单了:
代码语言:javascript复制VehicleFactory truckFactory = new TruckFactory();
Vehicle orderVehicle = truckFactory.orderVehicle("large", "blue");
3、抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是工厂方法模式的扩展版本。它不再是创建单一类型的对象,而是创建一系列相关联的对象,如果说工厂方法模式中只包含一个抽象产品类,那么抽象工厂模式则包含多个抽象产品类。所以说工厂方法模式只是抽象工厂模式的一种特例。
抽象工厂设计模式的实现如图 3-1 所示:
图 3-1
抽象工厂模式由以下类组成:
- AbstractFactory (抽象工厂类):抽象类,用于声明创建不同类型产品的方法。它针对不同的抽象产品类都有对应的创建方法。
- ConcreteFactory (具体工厂类):具体类,用于实现抽象工厂基类中声明的方法。针对每个系列的产品都有一个对应的具体工厂类。
- AbstractProduct(抽象产品类):对象所需要的基本接口或类。一簇相关产品类由来自不同层级的相似产品类组成。ProductA1 和 ProductB1 来自第一个类簇,由 ConcreteFactory1 实例化。ProductA2 和 ProductB2 来自第二个类簇,由 ConcreteFactory2 实例化。
结尾:
工厂的模式的核心就是右工厂类来负责合适对象的创建。如果工厂类很复杂,比如同时服务于多种类型的对象或工厂,也可以根据前面内容修改相应的代码。
下一节,分享建造者模式……