设计模式与实践:创建型模式(工厂模式)

创建型模式

  • 单例模式
  • 工厂模式
  • 建造者模式
  • 原型模式
  • 对象池模式

工厂模式

所谓工厂,我们可以理解为一个用来生产实例的工具,工厂负责生产一系列同一性质的产品。在调用的时候,我们把这个工厂看做一个黑盒,我们只要告诉它我们需要什么实例,他就会给我们创建对应的实例。

1. 静态工厂模式

我们写一个简单地工厂类来创建Vehicle实例。我们创建一个抽象Vehicle类和继承自它的三个具体类:Bike、Car和Truck。 工厂类(也叫做静态工厂类),代码如下:

public class VehicleFactory{
	//用来让开发者选择需要创建的对象的标志
	public enum VehicleType{
		Bike,
		Car,
		Truck;
	}
	public static Vehicle create(VehicleType type){
		if(type.equals(Vehicle.Bike) return new Bike();
		if(type.equals(Vehicle.Car) return new Car();
		if(type.equals(Vehicle.Truck) return new Truck();
		else return null;//这个else针对的是最后一个if
	}
}

这个静态工厂类逻辑简单,有好的地方:它只负责Vehicle类的实例化,符合单一职责原则,用户只需要调用Vehicle接口,符合了依赖倒置原则。但是不能很好的适应市场环境,真实开发过程中,可能会增加新的Vehicle类,这时候每增加一个Vehicle类就要对该VehicleFactory进行一次修改,这就违反了开闭原则(已经写好的类最好不要进行修改,只进行拓展)

所以我们需要对其进行修改,另其符合开闭原则,实现方法有下面两种:

  • 适用反射机制注册产品类对象和实例化
  • 注册产品对象并向每个产品添加newInstance()方法,该方法返回与自身类型相同的新实例。

1.1 使用反射机制进行类注册的简单工厂模式

为此,我们需要使用map对象来保存产品ID以及它对应的类

private Map<String,Class> registerdProducts = new HashMap<String,Class>();

然后,增加一个注册新Vehicle类的方法:

public void registerVehicle(String vehicleId,Class vehicleClass){
	registerdProducts.put(vehicleId,vehicleClass);
}

构造方法如下:

public Vehicle createVehicle(String type) throws InstantiationException,IllegalAccessException{
	Class productClass = registerdProducts.get(type);
	return (Vehicle) productClass.newInstance();
}

我们知道,使用反射会使得程序运行效率降低,有的情况下,反射机制并不适用,比如反射机制需要运行时权限,这导致有的特定环境下,反射获得实例无法实现。

在对性能要求很高的场景下,应该尽量避免使用这种机制。

1.2 使用newInstance方法进行类注册的简单工厂模式

每个产品类都可以创建自己的实例

首先在Vehicle基类中添加一个抽象方法:

abstract public Vehicle newInstance();

对于每种产品,基类(父类)声明为抽象的方法都要实现

@Override
public Car newInstance(){
	return new Car();
}

在工厂类中,更改map用于保存对象的ID以及它对应的Vehicle对象

private Map<String,Vehicle> registerdProducts = new HashMap<String,Vehicle>();

通过实例注册一种新的Vehicle类型:

public void registerVehicle(Sring vehicleId, Vehicle vehicle){
	registerdProducts.put(vehicleId,vehicle);
}

也要对应地改变Factory中的createVehicle方法:

public Vehicle createVehicle(String vehicleId){
	return registerdProducts.get(vehicleId).newInstance();
}

调用方法:

public class test{
	public static void main(String[] args){
		registerVehicles();

		//动态注册以后,就可以随时让工厂生产该实例
		Car car = (Car)VehicleFactory.createVehicle("Car");
	}

	pulic static void registerVehicles(){
		VehicleFactory.registerVehicle("Car",new Car());
		VehicleFactory.registerVehicle("Truck",new Truck());
	}
}

2. 工厂方法模式

工厂方法模式是在静态工厂模式上的改进。工厂类被抽象化,使用实例化特定产品类的代码被转移到实现抽象方法的子类中。这样不需要修改就可以拓展工厂类。

我们在抽象工厂类中不实现具体的实例化代码,而是交给抽象工厂类的实现类来完成,这样如果要拓展更多种实例,就只需要添加抽象工厂类的新实现,而不需要修改它,符合开闭原则。

比如我们有一个汽车工厂,目前只有两种车型,小型跑车和大型家用车,在软件中,顾客可以自由决定买什么样的车,首先小型车对应的Vehicle类的子类为SportCar,大型家用车对应的Vehicle子类为SedanCar。

创建Vehicle类结构之后就可以创建抽象工厂类。注意工厂类中没有创建实例的代码。

public abstract class VehicleFactory{

	//只允许子类访问,对外界隐藏,创建Vehicle,传入对应size参数
	protected abstract Vehicle createVehicle(String size);
	
	public Vehicle orderVehicle(String size, String color){
		Vehicle vehicle = createVehicle(size);
		vehicle.setColor(color);
		return vehicle;
	}
}

为了增加汽车实例化的代码,我们创建了VehicleFactory的子类,也就是CarFactory类,并且在CarFactory中实现从父类中调用的createVehicle抽象方法。实际上,我们可以理解为,VehicleFactory是一个总公司,它将具体的实例化需求委托给了分工厂。

public class CarFactory extends VehicleFactory{
	@Override
	protected Vehicle createVehicle(String size){
		if(size.equals("small") return new SportCar();
		else if(size.equals("big") return new SedanCar();
		return null;
	}
}

如此一来,在客户端,我们只需要创建工厂类并创建订单就可以了

VehicleFactory carFactory = new CarFactory();
carFactory.orderVehicle("big","blue");

如果我们另外增加了业务,比如还需要生产卡车,那我们就创建一个卡车工厂TruckFactory,负责卡车的实例化操作。

public class TruckFactory extends VehicleFactory{
	@Override
	protected Vehicle createVehicle(String size){
		if(size.equals("small")) return SmallTruck();
		else if(size.equals("big") return BigTruck();
		return null;
	}
}

调用手段一致

VehicleFactory truckFactory = new TruckFactory();
truckFactory.orderVehicle("small");

如果说业务量很少,那么我们不需要新建一个类来作为大工厂,只需要一个临时工厂,这里我们通过匿名具体工厂模式来实现。

Vehicle Factory tempFactory = new VehicleFactory(){
	@Override
	protected Vehicle createVehicle(String size){
		if(size.equals("small") return new SmallTempCar();
		else if(size.equals("big") return new BigTempCar();
		return null;
	}
}

tmepFactory.orderVehicle("big","blue");

3. 抽象工厂模式

抽象工厂模式工厂方法模式的扩展版本,它不再时创建单一类型的对象,而是创建一系列相关联的对象。如果说工厂方法模式中只包含一个抽象产品类,那么抽象工厂模式则包含多个抽象产品类。

注意到,抽象工厂模式是创建一系列相关联的对象。

比如题库工厂,语文方面有语文课本,语文天天练练习册,语文笔记本,语文单元卷,这是一系列相关联的对象,对应的英语方面,也有英语课本,英语天天练练习册,英语笔记本,英语单元卷。

用于实例化一系列相关联类的工厂继承自抽象工厂。

我们有抽象工厂类,规范了我们要创建对象的方法

public abstract class AbstractFactory{
	public AbstractTextBook createTextBook();
	public AbstractExerciseBook createExerciseBook();
	public AbstractNoteBook createNoteBook();
	public AbstractTestPaper createTestPaper();
}

接下来比如我们的目标是语文工厂,那么我们先定一下语文的相关类
CNTextBook类、CNExerciseBook类、CNNoteBook类、CNTestPaper类。

然后新建一个语文工厂负责创建该系列类

public class CNFactory extends AbstractFactory{
	@Override
	public AbstractTextBook createTextBook(){
		return new CNTextBook();
	}

	@Override
	public AbstractExerciseBook createExerciseBook(){
		return new CNExerciseBook();
	}

	@Override
	public AbstractNoteBook createNoteBook(){
		return new CNNoteBook();
	}

	@Override
	public AbstractTestPaper createTestPaper(){
		return new CNTestPaper();
	}
}

参考:
《Java设计模式及实践》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章