创建型设计模式之抽象工厂方法模式

时间:2022-10-02 19:55:24

1 抽象工厂方法模式概念

1.1 介绍

  随着客户的要求越来越高,宝马车需要不同配置的空调和发动机等配件。于是这个工厂开始生产空调和发动机,用来组装汽车。这时候工厂有两个系列的产品:空调和发动机。宝马320系列配置A型号空调和A型号发动机,宝马230系列配置B型号空调和B型号发动机。
  抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。比如宝马320系列使用空调型号A和发动机型号A,而宝马230系列使用空调型号B和发动机型号B,那么使用抽象工厂模式,在为320系列生产相关配件时,就无需制定配件的型号,它会自动根据车型生产对应的配件型号A。

1.2 定义

  为创建一组相关或者是相互依赖的对象提供一个接口,而不需要指定他们的具体实现类。

1.3 使用场景

  一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。例如:Linix和Windows下都有文本编辑器图片处理器,两者都属于Software软件的范畴,但是他们所在的操作系统不一样,代码的实现逻辑实现也是不同的,也就是具有了共同的约束条件:操作系统类型。于是我们可以使用抽象工厂模式,产生不同操作系统下的编辑器和图片处理器。

2 原型模式UML类图通用

创建型设计模式之抽象工厂方法模式

或者

创建型设计模式之抽象工厂方法模式

3 通用模式代码

(1)抽象产品类A

public abstract class AbstractProductA { 
// 每个具体产品子类需要实现的方法
public abstract void method();
}

(2)抽象产品类B

public abstract class AbstractProductB { 
// 每个具体产品子类需要实现的方法
public abstract void method();
}

(3)具体产品类A1

public class ConcreteProductA1 extends AbstractProductA {
@Override
public void method() {
System.out.println("具体产品类A1的实现方法");
}
}

(4)具体产品类A2

public class ConcreteProductA2 extends AbstractProductA {
@Override
public void method() {
System.out.println("具体产品类A2的实现方法");
}
}

(5)具体产品类B1

public class ConcreteProductB1 extends AbstractProductB {
@Override
public void method() {
System.out.println("具体产品类B1的实现方法");
}
}

(6)具体产品类B2

public class ConcreteProductB2 extends AbstractProductB {
@Override
public void method() {
System.out.println("具体产品类B2的实现方法");
}
}

(7)抽象工厂类

public abstract class AbstractFactory { 
// 创建A产品家族
public abstract AbstractProductA createProductA();
//创建B产品家族
public abstract AbstractProductB createProductB();
}

(8)具体工厂类1

public class ConcreteFactory1 extends AbstractFactory {
// 只生产产品等级为1的A产品
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}

// 只生产产品等级为1的B产品
public AbstractProductB createProductB() {
return new ConcreteProductB1();
}
}

(9)具体工厂类2

public class ConcreteFactory2 extends AbstractFactory {
// 只生产产品等级为2的A产品
public AbstractProductA createProductA() {
return new ConcreteProductA2();
}

// 只生产产品等级为2的B产品
public AbstractProductB createProductB() {
return new ConcreteProductB2();
}
}

4 Android源码中的原型模式

  抽象工厂模式在Android源码中使用较少,因为很少会出现多个产品种类的情况,大部分使用工厂方法模式即可解决。

(1)MediaPlayer
  MediaPlayer Factory分别会生成4个不同的MediaPlayer基类:StagefrightPlayer、NuPlayerDriver、MidiFile和TestPlayerStub,四者均继承于MediaPlayerBase。

5 抽象工厂方法模式实战

  虽然Q3、Q5、Q7都是一个车系,但是三者之间的零部件差别却是很大,例如,Q3使用的发动机是国产的,而Q7则是原装进口的;Q3轮胎是普通的轮胎,而Q7则使用的是全尺寸越野轮胎;还有Q3使用的是比较普通的制动系统,而Q7则使用的是制动性能极好的制动系统。Q3、Q7对应的是一系列车,而轮胎、发动机、制动系统则对应的是一系列零部件,两者是两种不同的产品类型,这时候就可以将抽象工厂模式应用到其中。首先汽车工厂需要生产轮胎、发动机、制动系统这3中部件。

(1)轮胎相关类

public interface ITire {
/**
* 轮胎
*/

void tire();
}
public class NormalTire implements ITire{
@Override
public void tire() {
System.out.println("普通轮胎");
}
}
public class SUVTire implements ITire{
@Override
public void tire() {
System.out.println("越野轮胎");
}
}

(2)发动机相关类

public interface IEngine {
/**
*发动机
*/

void engine();
}
public class DomesticEngine implements IEngine{
@Override
public void engine() {
System.out.println("国产发动机");
}
}
public class ImportEngine implements IEngine{
@Override
public void engine() {
System.out.println("进口发动机");
}
}

(3)制动系统相关类

public interface IBrake {
/**
*制动系统
*/

void brake();
}
public class NormalBrake implements IBrake{
@Override
public void brake() {
System.out.println("普通制动");
}
}
public class SeniorBrake implements IBrake{
@Override
public void brake() {
System.out.println("高级制动");
}
}

(4)抽象车厂类

public abstract class CarFactory {
/**
* 生产轮胎
*
* @return 轮胎
* */

public abstract ITire createTire();

/**
* 生产发动机
*
* @return 发动机
* */

public abstract IEngine createEngine();

/**
* 生产制动系统
*
* @return 制动系统
* */

public abstract IBrake createBrake();

}

(5)Q3工厂类

public class Q3Factory extends CarFactory{

@Override
public ITire createTire() {
return new NormalTire();
}

@Override
public IEngine createEngine() {
return new DomesticEngine();
}

@Override
public IBrake createBrake() {
return new NormalBrake();
}
}

(6)Q7工厂类

public class Q7Factory extends CarFactory{

@Override
public ITire createTire() {
return new SUVTire();
}

@Override
public IEngine createEngine() {
return new ImportEngine();
}

@Override
public IBrake createBrake() {
return new SeniorBrake();
}
}

(7)客户类

public class Client {
public static void main(String[] args) {
//Q3工厂类
CarFactory factoryQ3 = new Q3Factory();
factoryQ3.createTire().tire();
factoryQ3.createEngine().engine();
factoryQ3.createBrake().brake();
System.out.println("---------------");

//Q7工厂类
CarFactory factoryQ7 = new Q7Factory();
factoryQ7.createTire().tire();
factoryQ7.createEngine().engine();
factoryQ7.createBrake().brake();
}
}

(8)结果打印

普通轮胎
国产发动机
普通制动
------------------

越野轮胎
进口发动机
高级制动

  可以看出上面模拟了两个工厂,如果有了Q5厂、Q9厂,各自厂家生产的零部件型号种类又不相同,那么我们创建的类文件就会翻倍。这也是抽象工厂模式的一个弊端,所以实际开发中要权衡使用。

6 简单工厂、工厂方法、抽象工厂之区别

  简单工厂,工厂方法,抽象工厂都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,优化了系统的架构,并且增强了系统的扩展性。

6.1 区别

(1)简单工厂
  简单工厂模式的工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的对象实例。(不修改代码的话,是无法扩展的。)

(2)工厂方法
  工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。(在同一等级结构中,支持增加任意产品。)

(3)抽象工厂
  抽象工厂是应对产品族概念的。比如说:每个汽车公司可能要同时生产轿车,货车,客车,那么每一个工厂都要有创建轿车,货车和客车的方法。(应对产品族概念而生,增加新的产品线很容易,但是无法增加新的产品。)

6.2 举例说明

  用种蔬菜的例子来说明事实,最初的时候,由于规模小,只种植一种蔬菜,根菜类蔬菜,这个时候由于种植方式比较简单,采用简单工厂模式即可,主要目的是让工人轻松,下达工厂种植即可。
  但是随着种植厂的发展以及市场的需求,要增加一种蔬菜类型种植——茎菜,由于茎菜与根菜种植方式不一致,就需要两个专门的种植工厂来进行管理,那么久采用工厂模式来管理,一个工厂负责一种作物的种植,这个时候产品可以理解为仍然在一个层次。
  我用UML图表示三种结构:

(1)简单工厂

创建型设计模式之抽象工厂方法模式

(2)工厂方法

创建型设计模式之抽象工厂方法模式

(3)抽象工厂

创建型设计模式之抽象工厂方法模式

(4)小结

  在没一个层次,种菜工人所关心的对象也不一样,在简单工厂模式下,工人要想到种植萝卜还是白菜,在工厂模式下,工人想到是种植根菜还是茎菜,而在抽象工厂模式下,则关心种植基因菜还是非基因菜

7 总结

(1)优点

  分离接口与实现,客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已,使其从具体的产品实现中解耦,同时基于接口与实现分离,使抽象该工厂方法模式在切换产品类时更加灵活、容易。

(2)缺点

  一是对类文件的爆炸性增加,二是不太容易扩展新的产品类。

8 参考文章与链接

《Android源码设计模式解析与实战》

《设计模式之禅》

《Android源码设计模式解析与实战》读书笔记(六)

设计模式:简单工厂、工厂方法、抽象工厂之小结与区别

抽象工厂模式和工厂方法模式区别