【设计模式】-创建型模式-第2章第2讲-【工厂模式】

2022-12-02 15:48:59 浏览数 (1)

目录

场景描叙:

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 类和两个子类,子类分别为 SportCarSedanCar

代码语言: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 实例化。

结尾:

工厂的模式的核心就是右工厂类来负责合适对象的创建。如果工厂类很复杂,比如同时服务于多种类型的对象或工厂,也可以根据前面内容修改相应的代码。

下一节,分享建造者模式…… 

0 人点赞