初探设计模式——抽象工厂模式

145 阅读5分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。

1.模式动机

  • 工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体的产品,工厂方法模式具有唯一性。有时候我们需要一个工厂生产多种产品,工厂方法模式就无法满足这个需求,此时就需要引入抽象工厂模式,在了解抽象工厂模式前要先引入两个概念,【产品等级结构】和【产品族】,这两个概念一定要了解清楚才能对抽象工厂模式了解透彻。
    • 产品等级结构:可以理解为继承关系,例如一个抽象类是手机,具体产品就是小米手机,华为手机,那么抽象手机和具体品牌的手机就是一个产品等级结构,其中抽象手机是父类,具体品牌手机是子类。
    • 产品族:在抽象工厂模式中,由同一个工厂生产的,位于不同产品等级结构中的一组产品称为产品族,例如小米工厂生产了小米手机、小米电脑,华为工厂生产了华为手机、华为电脑。小米手机和小米电脑是由小米工厂生产的并且手机和电脑是不同的产品等级结构,因此是一个产品族,华为手机和华为电脑都是由华为工厂生产的,因此是一个产品族。
  • 当系统所提供的工厂所生产的产品并不是一个简单的对象,而是由多个位于不同产品等级结构中属于不同类型的产品时就需要用到抽象工厂模式了。

2.定义

提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体的类。

3.模式结构

抽象工厂模式包含4个角色:

  • 抽象工厂
  • 具体工厂
  • 抽象产品
  • 具体产品

4.时序图

5.代码分析

代码案例:假设现在有两个工厂,一个只能生产电脑,一个只能生产手机,现在因为订单需求,需要两个工厂既可以生产电脑也可以生产手机,此时工厂就要进行升级,升级中的关键点如下:

  • 抽象工厂:Factory
  • 具体工厂:XiaoMiFactory、HuaWeiFactory
  • 抽象产品:Product
  • 抽象产品,集成自抽象产品Product:Phone、Computer
  • 具体产品:XiaoMiPhone、XiaoMiComputer、HuaWeiPhone、HuaWeiComputer
  • 产品等级结构:Phone→XiaoMiPhone、HuaWeiPhone,Computer→XiaoMiComputer、HuaWeiComputer
  • 产品族:XiaoMiFactory→XiaoMiPhone、XiaoMiComputer,HuaWeiFactory→HuaWeiPhone、HuaWeiComputer
/**
 * 抽象工厂
 */
public static abstract class Factory {
    public abstract Product buildPhone();

    public abstract Product buildComputer();
}

/**
 * 小米工厂
 */
public static class XiaoMiFactory extends Factory {

    @Override
    public Product buildPhone() {
        return new XiaoMiPhone();
    }

    @Override
    public Product buildComputer() {
        return new XiaoMiComputer();
    }
}

/**
* 华为工厂
 */
public static class HuaWeiFactory extends Factory {

    @Override
    public Product buildPhone() {
        return new HuaWeiPhone();
    }

    @Override
    public Product buildComputer() {
        return new HuaWeiComputer();
    }
}

/**
 * 抽象产品
 */
public static abstract class Product {
    public abstract void buildProduct();
}

/**
 * 继承自抽象产品Product的抽象Phone
 */
public static abstract class Phone extends Product {
    @Override
    public abstract void buildProduct();
}

/**
 * 继承自抽象产品Product的抽象Computer
 */
public static abstract class Computer extends Product {
    @Override
    public abstract void buildProduct();
}

/**
 * 小米手机
 */
public static class XiaoMiPhone extends Phone {

    @Override
    public void buildProduct() {
        System.out.println("生产了小米手机");
    }
}

/**
 * 小米电脑
 */
public static class XiaoMiComputer extends Computer {

    @Override
    public void buildProduct() {
        System.out.println("生产了小米电脑");
    }
}

/**
 * 华为手机
 */
public static class HuaWeiPhone extends Phone {

    @Override
    public void buildProduct() {
        System.out.println("生产了华为手机");
    }
}

/**
 * 华为电脑
 */
public static class HuaWeiComputer extends Computer {

    @Override
    public void buildProduct() {
        System.out.println("生产了华为电脑");
    }
}

public static void main(String[] args) {
    Factory xiaoMiFactory = new XiaoMiFactory();
    Factory huaWeiFactory = new HuaWeiFactory();

    xiaoMiFactory.buildPhone().buildProduct();
    xiaoMiFactory.buildComputer().buildProduct();

    huaWeiFactory.buildPhone().buildProduct();
    huaWeiFactory.buildComputer().buildProduct();
}

运行结果如下:
生产了小米手机
生产了小米电脑
生产了华为手机
生产了华为电脑

6.优点

  • 由于具体工厂实现了抽象工厂中定义的所有公共接口,因此只要修改了具体工厂中创建的实例,就可以在某种意义上改变整个软件系统的行为。
  • 应用抽象工厂模式可以实现高内聚低耦合的设计目的。
  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
  • 增加一个具体工厂模式和产品组很方便,无需修改已有系统,符合【开闭原则】。

7.缺点

  • 添加新的产品对象困难,因为在抽象工厂角色创建时就已经规定了所有可以被创建的公共接口,如果要增加新的产品对象那么就要修改这个抽象工厂,但是一旦修改了抽象工厂那就意味着所有继承自这个抽象工厂的具体工厂都要进行修改,这样就很麻烦了。说的更简单点就是添加一个新的具体工厂和产品族很容易,添加一个新的产品等级结构很难。

8.适用环境

  • 一个系统中有多个产品族并且每次只使用一个产品族。
  • 属于同一个产品族的产品将在一起使用,这必须在系统设计中提现出来。
  • 系统提供一个产品类的库,所有产品都以同样的接口出现,从而使客户端不依赖于具体实现。

9.扩展

  • 开闭原则的倾斜性:开闭原则要求系统对扩展开放对修改关闭,因此当系统中要增加一个新的产品族时只需要增加一个新的具体工厂即可,但是要增加产品等级结构就会很麻烦,因为这样做就需要修改抽象工厂,修改抽象工厂就意味着要修改所有集成了它的子类,这显然违背了开闭原则。
  • 抽象工厂模式的退化:如果具体工厂中只有一个产品对象,也就是只有一个产品等级结构时就无需使用抽象工厂模式,使用工厂方法模式会更好;如果把抽象工厂和具体工厂合并为一个工厂来创建产品对象并且将创建对象的工厂方法设计成静态时就可以使用简单工厂模式会更好。

参考链接:抽象工厂模式