相关概念:
抽象工厂方法模式是工厂方法模式的一个特例。
定义:工厂方法模式(FACTORY METHOD)是一种常用的对象创建型设计模式,此模式的核心精神是封装类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂;具体工厂;抽象产品;具体产品。
抽象工厂(Creator):是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
具体工厂(Concrete Creator):这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。
抽象产品(Product):工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。
具体产品(Concrete Product):这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
抽象工厂方法模式:为创建一组相关或者相互依赖的对象提供一个接口,而不需要指定它们的具体类。每个抽象产品都对应一个或多个具体的产品,每个抽象工厂都对应一个或多个具体工厂,包含四个基本角色。
适用场景:
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。
由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。
工厂方法模式和Builder模式的异同:
这两种模式都是为了创建复杂对象而设计的模式
工厂方法模式用来生成一系列同类型的复杂对象(如:汽车生产工厂生产汽车),复杂对象的创建过程在工厂方法中,并且可以管理一系列的生成的产品等,当一个工厂只生产一种类型的产品,生产出来的产品类型相同。
Builder模式是用来生成一个更为复杂对象(这种类型的对象具有不同的表现),将复杂对象的创建与展示相分离,将对象的创建过程封装以向外界隐藏起来,使得同样的构建过程可以创建不同的表示。
实现代码:
抽象产品
/**
* 抽象产品
* @author lt
*
*/
public abstract class Product {
/**
* 每个产品都应该有它的用途
*/
public abstract void use();
}
抽象工厂
/**
* 抽象工厂
* @author lt
*
*/
public abstract class Factory {
/**
* Product是要生成的产品的一个抽象类,即抽象产品
* @return Product
*/
public abstract Product createProduct();
}
具体产品
/**
* 具体产品
* @author lt
*
*/
public class Car extends Product{
protected void run(){
System.out.println("汽车跑起来了");
}
protected void stop(){
System.out.println("汽车停下来了");
}
@Override
public void use() {
System.out.println("一种交通工具");
}
}
具体工厂
/**
* 具体工厂,这里是汽车生产工厂
* @author lt
*
*/
public class CarFactory extends Factory{
/**
* Car是具体产品,是产品的一个子类
* @return
*/
@Override
public Car createProduct() {
return new Car();
}
}
具体工厂里面可以封装一些产品创建过程中需要做的操作,如:将生产的产品添加到一个集合中,以便后期管理。
测试:
public static void main(String[] args) {
Factory factory = new CarFactory();
Car car = (Car) factory.createProduct();
car.use();
car.run();
car.stop();
}
可以看到这里的工厂是抽象工厂(接口),但实际上是具体的工厂(实例),那么它实际生产出来的产品也是具体产品(让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类),这里的具体产品是汽车。
结果:
上面的这些代码是工厂方法模式的完整的形式,工厂方法的完整描述:定义一个创建对象的接口(即抽象工厂类)实例化抽象类(抽象产品),让其子类(具体工厂类)决定实例化哪一个类(具体产品类)。“一对一”的关系。,由四个角色组成。
除了上面的四个角色组成的工厂方法模式外,还有简单工厂方法模式或者说是静态工厂方法模式。
我们对上面的代码进行一些改造
在具体工厂CarFactory中添加一个方法:
public <T extends Object> T createCar(Class<T> clazz){
T obj = null;
try {
obj = (T) Class.forName(clazz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
也可以为每一种具体的汽车写一个生产方法,这里为了简单起见,利用反射根据传递进来的类字节码生成类(具体产品)的实例。
如果这个方法写成静态
static
的,那么这个工厂就是简单工厂或者静态工厂了,相应的模式为简单工厂方法模式或静态工厂方法模式。
具体产品A,宝马汽车
/**
* 具体产品,宝马汽车
* @author lt
*
*/
public class BaoMa extends Car{
@Override
protected void run() {
System.out.println("宝马跑起来了!");
}
@Override
protected void stop() {
System.out.println("宝马停下来了!");
}
}
具体产品B,奔驰汽车
/**
* 具体产品,大奔
* @author lt
*
*/
public class BenChi extends Car{
@Override
protected void run() {
System.out.println("奔驰跑起来了!");
}
@Override
protected void stop() {
System.out.println("奔驰停下来了!");
}
}
测试:
public static void main(String[] args) {
CarFactory factory = new CarFactory();
BaoMa baoma = factory.createCar(BaoMa.class);
baoma.run();
baoma.stop();
BenChi benchi = factory.createCar(BenChi.class);
benchi.run();
benchi.stop();
}
结果:
最简单的一个工厂方法模式是静态工厂方法模式,即不含有任何抽象,相应的方法为static的,这个模式在Android开发中用一个工厂管理多个Fragment的时候用到过。
总结:
工厂方法模式中的抽象工厂方法模式具有如下优缺点:
抽象工厂方法模式优点:
分离接口与实现,耦合性低。要客户端使用抽象工厂来创建需要的对象,如客户端不需要知道具体的实现是谁,客户端只是面向接口编程,使其在具体的产品实现中解耦。
灵活性高,极易扩展。由于是基于接口与实现的分分离,使得抽象工厂方法模式在切换同类型的产品类的时候更加灵活,更加简单。
抽象工厂方法模式缺点:
类文件爆炸性增加。每当有一个具体产品与其他具体产品不同时都需要对应的一个具体工厂。
不太容易扩展新类型的产品。因为我们增加一个新类型的产品类时候就需要修改抽象工厂,抽象工厂更改后,那么对应的具体的工厂类均要被修改,甚至当新类型的产品类和原来的产品类截然不同时,就需要一个添加一个新的抽象工厂。