「聊设计模式」之抽象工厂模式(Abstract Factory)

举报
bug菌 发表于 2023/09/25 16:16:11 2023/09/25
【摘要】 抽象工厂模式是一种通过接口或抽象类来创建一系列相关或依赖对象的设计模式。它是工厂方法模式的扩展,它可以创建多个产品族,而工厂方法模式只能创建单个产品族。抽象工厂模式通过将工厂的抽象与产品的抽象相匹配来实现这一目标。

🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!


大家下午好,我是bug菌,今天我们继续聊设计模式。

前言

  在软件开发中,设计模式是一种被广泛使用的经验总结,它们为我们提供了一套已经经过验证的,可以复用的解决方案,可以帮助开发人员有效地解决常见问题,提高软件质量和可维护性。

  本文将介绍抽象工厂模式(Abstract Factory),这是一种创建型设计模式,它提供了一种创建与一组相关对象的方式,而无需指定其具体类。本文将详细介绍抽象工厂模式的概念、实现方法以及测试用例,并展示它在Java中的实现。

摘要

  抽象工厂模式是一种通过接口或抽象类来创建一系列相关或依赖对象的设计模式。它是工厂方法模式的扩展,它可以创建多个产品族,而工厂方法模式只能创建单个产品族。抽象工厂模式通过将工厂的抽象与产品的抽象相匹配来实现这一目标。

抽象工厂模式

概念

  抽象工厂模式是一种创建型设计模式,它提供了创建一组相关或依赖对象的接口,无需指定它们具体的类。它通过将工厂的抽象与产品的抽象相匹配来实现这一目标。

  抽象工厂模式是在工厂方法模式的基础上发展而来的。工厂方法模式只能创建单个产品族,而抽象工厂模式可以创建多个产品族。在抽象工厂模式中,每个工厂类只负责创建对应产品族的产品,在工厂内部,通过抽象产品的公共接口来实现不同产品族的产品创建。

结构

抽象工厂模式包含以下结构:

  1. 抽象工厂(Abstract Factory):定义了一组工厂方法来创建一系列相关或依赖对象的抽象接口。

  2. 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建一系列相关的产品对象。

  3. 抽象产品(Abstract Product):定义了产品对象的抽象接口。

  4. 具体产品(Concrete Product):实现了抽象产品接口,是由相关的具体工厂创建的对象。

  5. 客户端(Client):使用抽象工厂和抽象产品接口来调用具体工厂创建产品对象的方法,实现对一系列相关或依赖对象的创建和使用。

如下是抽象工厂模式的UML类图:

image.png

优缺点

优点

抽象工厂模式的优点如下:

  1. 可以保证一系列相关对象的一致性,确保这些对象按照一定的规则和要求组合在一起。

  2. 客户端与工厂分离,客户端只需要知道工厂接口即可,与具体的产品无关,可以很方便地切换产品簇,以适应不同的需求。

  3. 扩展性好,可以很方便地添加新的产品簇。

缺点

抽象工厂模式的缺点如下:

  1. 如果要增加一个新的产品,除了要增加一个新的产品类之外,还需要修改所有工厂类,增加相应的创建方法,违反了“开放-封闭原则”。

  2. 在增加新的产品簇时,需要增加大量的代码,不利于代码的维护和管理。

  总的来说,抽象工厂模式适合于产品簇比较固定,但是需要支持不同产品簇切换的场景。如果需要添加新的产品,或者产品簇数量过多,不适用于抽象工厂模式。

应用场景

抽象工厂模式适用于以下场景:

  1. 需要一个产品家族的产品对象,这些产品对象之间有比较高的关联性,而且这些产品对象有共同的约束条件。

  2. 希望在不同的产品系列中选择一个产品来创建一组对象时,可以使用抽象工厂模式。

  3. 需要在运行时切换不同的产品系列时,可以使用抽象工厂模式。

  4. 在一个系统中,需要独立于其产品的创建、组合和表示时,可以使用抽象工厂模式。

  例如,在一个汽车配件生产厂家中,可能存在多个系列的轮胎、发动机、座椅等产品,每个系列的产品都有自己的特点,并且需要满足一定的约束条件,那么我们可以使用抽象工厂模式,将每个系列的产品抽象为一个工厂,再通过工厂方法来创建对应系列的产品,这样就可以保证每个系列的产品对象之间有着比较高的关联性,并且可以避免在创建和组合产品时出现冗余的代码。

模式实现

如下我给大家用代码亲自演示一下抽象工厂模式,具体请看如下代码:

1. 创建抽象工厂类

  抽象工厂类中需要定义用于创建产品族的抽象方法,抽象方法返回抽象产品。在Java中,可以使用抽象类或接口来定义抽象工厂。

package com.example.javaDesignPattern.abstractFactory;

/**
 * 抽象工厂类
 *
 * @author bug菌
 * @version 1.0
 * @date 2023/9/18 17:29
 */
public abstract class AbstractFactory {
    public abstract ProductA createProductA();
    public abstract ProductB createProductB();
}

2. 创建具体工厂类

  具体工厂类实现抽象工厂类中定义的抽象方法,用于创建具体的产品。具体工厂类中也可以包含额外的方法和属性,用于定制化产品的创建。

如下创建第一个具体工厂类,示例代码如下:

package com.example.javaDesignPattern.abstractFactory;

/**
 * 创建具体工厂类
 *
 * @author bug菌
 * @version 1.0
 * @date 2023/9/18 17:30
 */
public class ConcreteFactory1 extends AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }
    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}

如下接着创建第二个具体工厂类,示例代码如下:

package com.example.javaDesignPattern.abstractFactory;

/**
 * 创建具体工厂类
 *
 * @author bug菌
 * @version 1.0
 * @date 2023/9/18 17:30
 */
public class ConcreteFactory2 extends AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }
    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}

3. 创建抽象产品类

  抽象产品类定义产品的公共接口,从而使不同具体产品类可以实现相同的接口。

public abstract class ProductA {
    public abstract void display();
}
public abstract class ProductB {
    public abstract void show();
}

  以上代码是创建抽象类的示例。抽象类是不能被实例化的类,只能被继承,因此抽象类通常用于作为其他类的基类。在以上代码中,ProductAProductB都是抽象类。

  在ProductA类中,定义了一个抽象方法display(),该方法没有具体的实现,只有方法签名。所有继承自ProductA的子类在实现该方法时,需要给出具体的实现。由于抽象类不能被实例化,因此使用抽象方法可以让子类在具体实现时覆盖基类的实现,实现多态性。

  在ProductB类中,同样定义了一个抽象方法show()。和ProductA类中的display()方法类似,子类需要实现show()方法以满足多态性的需求。

  需要注意的是,抽象类中可以包含非抽象方法和属性,在子类继承后可以直接使用,不需要覆盖实现。

4. 创建具体产品类

  具体产品类实现抽象产品类中定义的抽象方法,用于实例化具体的产品。

public class ConcreteProductA1 extends ProductA {
    @Override
    public void display() {
        System.out.println("ConcreteProductA1 display");
    }
}
public class ConcreteProductB1 extends ProductB {
    @Override
    public void show() {
        System.out.println("ConcreteProductB1 show");
    }
}
public class ConcreteProductA2 extends ProductA {
    @Override
    public void display() {
        System.out.println("ConcreteProductA2 display");
    }
}

public class ConcreteProductB2 extends ProductB {
    @Override
    public void show() {
        System.out.println("ConcreteProductB2 show");
    }
}

  在如上代码,ConcreteProductA1ConcreteProductA2继承了抽象产品类ProductA,分别实现了抽象产品类中的display()方法;ConcreteProductB1ConcreteProductB2继承了抽象产品类ProductB,分别实现了抽象产品类中的show()方法。这些具体产品类将被工厂类使用来创建具体产品对象。

5. 创建客户端代码

  客户端代码使用抽象工厂来获取其需要使用的产品,客户端代码不需要知道如何创建产品,只需要知道如何使用它们。

package com.example.javaDesignPattern.abstractFactory;

/**
 * 创建客户端
 *
 * @author bug菌
 * @version 1.0
 * @date 2023/9/18 17:33
 */
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        AbstractFactory factory2 = new ConcreteFactory2();

        ProductA productA1 = factory1.createProductA();
        ProductB productB1 = factory1.createProductB();
        productA1.display();
        productB1.show();

        ProductA productA2 = factory2.createProductA();
        ProductB productB2 = factory2.createProductB();
        productA2.display();
        productB2.show();
    }
}

  客户端展示了抽象工厂模式的使用。客户端通过创建具体工厂对象(ConcreteFactory1ConcreteFactory2)来获得不同种类的产品对象(ProductAProductB)。客户端并不直接使用产品对象,而是通过工厂对象创建产品对象并调用它们的方法(display()show())。这样可以封装产品对象的创建过程,使得客户端只需要关注工厂对象和产品对象的接口,而不需要了解具体实现细节。

启动客户端测试结果如下:

image.png

代码方法解读

  其中,抽象工厂 AbstractFactory 定义了两个抽象方法 createProductA()createProductB(),分别用于创建产品 A 和产品 B。具体的工厂类ConcreteFactory1ConcreteFactory2 分别实现了这两个方法,并且分别用于创建不同的产品。

  在 Client 类的 main() 方法中,首先分别创建了 ConcreteFactory1ConcreteFactory2 两个工厂的实例。接着,通过这两个工厂实例的 createProductA()createProductB() 方法创建了不同的产品对象,并分别调用了它们的 display()show() 方法。

  因此,抽象工厂模式的主要优点是能够提供一致的产品族创建接口,使得客户端可以方便地创建一组相关的产品。同时也能遵循开闭原则,使得增加新的产品族比较容易,但同时也增加了类的数量,降低了系统的灵活性和可扩展性。

小结

  抽象工厂模式是用于创建一组相关或依赖对象的设计模式,它提供了一种创建产品族的方式,而无需指定具体的类。抽象工厂模式是在工厂方法模式的基础上发展而来,可以创建多个产品族。在抽象工厂模式中,每个工厂类只负责创建对应产品族的产品,通过抽象产品的公共接口来实现不同产品族的产品创建。抽象工厂模式的优点是可以保证一系列相关对象的一致性,客户端与工厂分离,扩展性好,缺点是如果要增加一个新的产品,除了要增加一个新的产品类之外,还需要修改所有工厂类,且在增加新的产品簇时,需要增加大量的代码。抽象工厂模式适用于需要一组产品对象,且这些对象之间有比较高的关联性,需要在不同的产品系列中选择一个产品来创建一组对象时,需要在运行时切换不同的产品系列,需要独立于其产品的创建、组合和表示时。在代码实现方面,需要定义抽象工厂类和抽象产品类,具体工厂类和具体产品类实现抽象工厂和抽象产品的方法。客户端通过创建具体工厂对象来获得不同种类的产品对象,而不需要了解具体实现细节。

附录源码

  如上涉及代码均已上传同步在GitHub,提供给同学们参考性学习。

总结

  本文着重介绍了抽象工厂模式,该模式是创建型设计模式的一种,它提供了一种创建一组相关或依赖对象的方式,无需指定其具体类。抽象工厂模式是工厂方法模式的扩展,可以创建多个产品族,而工厂方法模式只能创建单个产品族。

  为了实现抽象工厂模式,需要先创建抽象工厂类,其中定义用于创建产品族的抽象方法,抽象方法返回抽象产品。具体工厂类实现抽象工厂类中定义的抽象方法,用于创建具体的产品。抽象产品类定义产品的公共接口,具体产品类实现抽象产品类中定义的抽象方法,用于实例化具体的产品。

  在客户端代码中,使用抽象工厂来获取需要使用的产品,不需要知道如何创建产品,只需要知道如何使用它们。

  抽象工厂模式可以帮助开发人员有效地解决常见问题,提高软件质量和可维护性,是软件开发中经常使用的一种设计模式。

☀️建议/推荐你


  如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!

  最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

  同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。

📣关于我

  我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。