首页 > 其他分享 >抽象工厂模式:角色解析与应用探索

抽象工厂模式:角色解析与应用探索

时间:2023-12-11 11:03:03浏览次数:33  
标签:Human 角色 模式 工厂 抽象 产品 解析 public

抽象工厂模式:角色解析与应用探索_抽象工厂模式


抽象工厂模式:角色解析与应用探索_抽象工厂模式_02

前言

工厂模式一般指的是简单工厂模式、工厂方法模式、抽象工厂模式,这是三种工厂模式的最后一篇,其他两种的文章链接如下:

设计模式之是简单工厂模式_凡夫编程的技术博客_51CTO博客

工厂方法模式:改变你对软件开发的认知_凡夫编程的技术博客_51CTO博客

建议三种模式放在一起对比学习,更能领会其中的奥秘。看懂UML类图,更是奥秘中的奥秘哦,在UML类图中不同的箭头和线条,代表的意义是不同的,发现有很多人都画错了,这里简单的梳理了一下,如果需要可以移步这里:工厂方法模式:改变你对软件开发的认知_凡夫编程的技术博客_51CTO博客

什么是抽象工厂模式?

抽象工厂模式是一种创建型的工厂模式,它提供了一个接口,使客户端可以在不指定具体产品的情况下创建多个产品组中的产品对象。当存在多个抽象角色时,抽象工厂模式可以用来创建一个工厂,该工厂能够根据需要生成相应类型的产品。这种模式将产品的生成和使用解耦,使得客户端无需了解具体产品的实现细节。

抽象工厂模式的核心思想是将工厂封装成了一个抽象接口,通过这个接口来创建产品。它允许客户端通过调用抽象工厂的接口来生成多个产品族中的产品对象,而无需知道每个产品族的实现细节。抽象工厂模式适用于存在多个产品族的情况,这些产品族具有不同的实现,但是客户端需要使用多个产品族中的产品。通过使用抽象工厂模式,客户端可以灵活地使用不同的产品族,而无需对代码进行大量修改。

与工厂方法模式有什么区别?

抽象工厂模式和工厂方法模式都是设计模式中的对象创建型模式,主要用于封装对象的创建过程,以减少代码耦合。两种模式之间存在以下区别:

  1. 工厂角色不同:在工厂方法模式中,工厂方法是实现客户端与具体产品类解耦的关键,客户端通过继承或实现工厂方法实现创建产品的功能。而在抽象工厂模式中,抽象工厂是客户端与具体产品类解耦的关键,客户端通过实例化抽象工厂对象并调用其创建产品的方法实现创建产品的功能。
  2. 创建产品的模式不同:工厂方法模式中,每个具体工厂类只能创建一个具体产品类的实例,即“一对一”的关系。而在抽象工厂模式中,每个具体工厂类可以创建多个具体产品类的实例,即“一对多”的关系。
  3. 产品类型不同:在工厂方法模式中,工厂方法返回的产品类型是固定的,即每个具体工厂类只能创建一个固定类型的产品。而在抽象工厂模式中,抽象工厂返回的产品类型可以是多种多样的,即每个具体工厂类可以创建多个不同类型的产品。

总之,抽象工厂模式相对于工厂方法模式,更适用于创建一系列相关或相互依赖的对象,以及对产品进行分类和组织的情况。

抽象工厂UML类图

在抽象工厂模式中,存在四种角色:

  1. 抽象工厂角色(Abstract Factory):担任这个角色的是工厂方法模式的核心,它是与应用系统业务逻辑无关的。抽象工厂包含对多个产品结构的声明,任何工厂类都必须实现这个接口。
  2. 具体工厂角色(Concrete Factory):这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的业务逻辑紧密相关的。具体工厂类是抽象工厂的一个实现,负责实例化某个产品族中的产品对象。
  3. 抽象产品角色(Abstract Product):担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。抽象模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
  4. 具体产品角色(Concrete Product):抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。

抽象工厂模式:角色解析与应用探索_抽象工厂模式_03

抽象工厂实现示例

还以女娲造人的传说举一个例子:刚开始造人,女娲觉得还挺有意思的,造的时间长了,都是黄皮肤的中国人,显得很单调,没啥意思了,于是拓展了一下业务,开始造黑色皮肤的非洲人了,用抽象工厂模式来演示这个过程会是什么样呢?

UML类图如下:

抽象工厂模式:角色解析与应用探索_java_04

伪代码示例如下:

public interface Human {    /**     * 人类会吃东西     */
    void eat();

    /**
     * 人类会喝东西
     */
    void drink();
}
public class YellowMan implements Human {
    @Override
    public void eat() {
        System.out.println("黄色皮肤的中国男人在吃东西");
    }

    @Override
    public void drink() {
        System.out.println("黄色皮肤的中国男人在喝水");
    }
}
public class YelloWoman implements Human {
    @Override
    public void eat() {
        System.out.println("黄色皮肤的中国女人在吃东西");
    }

    @Override
    public void drink() {
        System.out.println("黄色皮肤的中国女人在喝水");
    }
}
public interface HumanFactory {

    Human createMan();

    Human createWoman();
}
public class YelloHumanFactory implements HumanFactory{
    @Override
    public Human createMan() {
        return new YellowMan();
    }

    @Override
    public Human createWoman() {
        return new YelloWoman();
    }
}
public class BlackHumanFactory implements HumanFactory{
    @Override
    public Human createMan() {
        return new BlackMan();
    }

    @Override
    public Human createWoman() {
        return new BlackWoman();
    }
}
public class Test {
    public static void main(String[] args) {
        HumanFactory yellowHumanFactory=new YelloHumanFactory();
        Human man = yellowHumanFactory.createMan();
        Human woman = yellowHumanFactory.createWoman();
        man.eat();
        man.drink();
        woman.eat();
        woman.drink();
        HumanFactory blackHumanFactory=new BlackHumanFactory();
        Human man1 = blackHumanFactory.createMan();
        Human woman1 = blackHumanFactory.createWoman();
        man1.eat();
        man1.drink();
        woman1.eat();
        woman1.drink();
    }
}

女娲这都造人业务都拓展到海外了,光能造黄种人、黑种人怎么行,还想造白种人怎么办呢?很简单:

1、实现Human接口,再实现一个白种男人、一个白种女人的类;

2、实现HumanFactory接口,再实现一个白种人的制造工厂;

public class WhiteMan implements Human {
    @Override
    public void eat() {
        System.out.println("白种欧洲男人吃东西");
    }

    @Override
    public void drink() {
        System.out.println("白种欧洲男人在喝水");
    }
}
public class WhiteWoman implements Human {
    @Override
    public void eat() {
        System.out.println("白种欧洲女人在吃东西");
    }

    @Override
    public void drink() {
        System.out.println("白种欧洲女人在喝水");
    }
}
public class WhiteHumanFactory implements HumanFactory{
    @Override
    public Human createMan() {
        return new WhiteMan();
    }

    @Override
    public Human createWoman() {
        return new WhiteWoman();
    }
}
public class Test {
    public static void main(String[] args) {
        HumanFactory whiteHumanFactory=new WhiteHumanFactory();
        Human man2 = whiteHumanFactory.createMan();
        Human woman2 = whiteHumanFactory.createWoman();
        man2.eat();
        man2.drink();
        woman2.eat();
        woman2.drink();
    }
}

有一天女娲觉得光造些男人、女人太单调了,男人、女人之间老是干架,怎么调合一下呢?那就造一些可爱小朋友吧。这时就会发现,如果还使用抽象工厂模式,就会很尴尬:HumanFactory接口里只有造男人、造女人的抽象方法,如果再加一个造小朋友的接口,就要对HuanFactory接口及其实现类具体工厂修改,这就破坏了开闭原则。如果除了造黑人、白人、黄人外,还想造点绿巨人,其实倒还好,和增加造白人的逻辑一样。这就是在决定是否使用抽象工厂模式的秘密所在,如果要扩展的是一个产品族,比较简单且适用,如果想丰富某一产品族的某个产品系列,就比较麻烦了;

抽象工厂应用场景

有没有发现这种方式非常好?完全符合开闭原则,无须对原有系统进行修改;下面就总结一下抽象工厂模式的实际应用场景有哪些?

  1. 产品组装:在现实生活中,抽象工厂模式最典型的例子就是产品的组装。例如,在电脑的组装过程中,我们通常需要选择一系列的配件,如CPU、硬盘、内存、主板、电源、机箱等。选择不同的配件,组装出来的电脑是不同的,这就可以看作是在使用不同的工厂来生产不同的产品。
  2. 提供产品类库:如果我们需要提供一个产品类库,但只想显示它们的接口而不是实现,那么就可以使用抽象工厂模式。例如,在设计一个绘图软件时,我们可能希望提供一个图形类库,但并不想暴露出每个图形的具体实现细节,这时就可以使用抽象工厂模式来生成各种图形对象。
  3. 多产品系列:如果一个系统需要由多个产品系列中的一个来配置,那么也可以使用抽象工厂模式。例如,在汽车制造中,可能需要根据用户的选择来配置不同的汽车模型。
  4. 独立于产品的创建、组合和表示:如果一个系统需要独立于它的产品的创建、组合和表示,那么也可以使用抽象工厂模式。例如,在开发一个游戏引擎时,我们可能希望游戏开发者能够使用我们提供的引擎来创建各种类型的游戏,而无需关心游戏引擎底层的具体实现。

总结

抽象工厂模式是一种设计程序时的工程方法,前面也说过,方法是为了解决问题的,不是灵丹妙药,用上了就一定很好,是绝不能生搬硬套的,重在理解和灵活运用。

对于抽象工厂模式有以下优点:

  1. 隔离了具体类的生成,使得客户端并不需要知道什么被创建。
  2. 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
  3. 增加新的产品族很方便,无须修改已有系统,符合开闭原则。

抽象工厂模式也有一些缺点:

  1. 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,违背了开闭原则。
  2. 如果客户端需要创建多个产品族的多个对象,那么代码会变得很冗长和复杂。
  3. 如果产品族之间有依赖关系,那么需要仔细考虑如何处理这些依赖关系,以避免出现循环依赖或其他问题。

因此,在使用抽象工厂模式时,需要根据具体的情况来考虑其优缺点,并决定是否使用该模式。

标签:Human,角色,模式,工厂,抽象,产品,解析,public
From: https://blog.51cto.com/fanfu1024/8768693

相关文章

  • mysql中count函数的几种写法解析
    一、count(主键)innodb引擎会遍历整张表,把每一行的主键值都取出来返回给服务层,服务层拿到主键后直接按行进行计数累加二、count(特定字段)2.1没有notnull约束innodb引擎会遍历整张表,把每一行的字段值都取出来返回给服务层,服务层判断是否为null,不为null计数累加2.2有no......
  • 深入解析Jenkins流水线:构建、部署和自动化交付
    enkins是一个强大的开源自动化服务器,而Jenkins流水线(JenkinsPipeline)是一种以代码为基础的自动化方式,允许您定义和管理CI/CD过程。在本文中,我们将深入探讨Jenkins流水线的各个方面,包括其基本概念、语法、构建、部署以及实现自动化交付的最佳实践。第1部分:基本概念和语法1.1什么是......
  • 云手机概念 云手机服务器的底层开发解析
    云手机服务器的底层开发解析作为一个语言模型,我可以提供一般性的了解和常见的云手机服务器技术细节,但无法提供特定云手机服务器的详细底层开发解析。以下是一些常见的云手机服务器技术和相关细节:虚拟化技术:云手机服务器通常使用虚拟化技术,如容器化或虚拟机(VM)来创建和管理虚拟......
  • 小谈设计模式(16)—抽象工厂模式
    (小谈设计模式(16)—抽象工厂模式)专栏介绍主要对目前市面上常见的23种设计模式进行逐一分析和总结,希望有兴趣的小伙伴们可以看一下,会持续更新的。希望各位可以监督我,我们一起学习进步,加油,各位。抽象工厂模式抽象工厂模式(AbstractFactoryPattern)是一种创建型设计模式,它提供了......
  • 深度解读DBSCAN聚类算法:技术与实战全解析
    探索DBSCAN算法的内涵与应用,本文详述其理论基础、关键参数、实战案例及最佳实践,揭示如何有效利用DBSCAN处理复杂数据集,突破传统聚类限制。关注TechLead,分享AI全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里......
  • 宝塔面板申请ssl证书验证失败,域名解析错误或验证URL无法被访
    一、问题描述使用宝塔面板建立站点,申请let‘sEncrypt免费ssl证书时提示验证失败,域名解析错误或验证URL无法被访!网上找了各种方案检查防火墙配置,安全组配置,域名解析,nginx代理等等乱七八糟的配置检查来检查去发现都没问题,后来我注意到,这个错误提示是去访问本站点内的一个文......
  • 学C笔记归纳 第九篇——分支循环语句3_for_while_do while(附九九乘法表解析和三种方式
     基础语法模版:while(1 条件控制语句){2 语句序列;}顺序:121212....21 do{ 1语句序列; }while(2 循环控制表达式);顺序:121212....12  for(1 初始化表达式;2 条件控制语句;4 调整表达式){3......
  • Spring Boot学习随笔- 集成JSP模板(配置视图解析器)、整合Mybatis(@MapperScan注解的使用
    学习视频:【编程不良人】2021年SpringBoot最新最全教程第五章、JSP模板集成5.1引入JSP依赖<!--引入jsp解析依赖--><!--C标签库--><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></depen......
  • 解析几何笔记:平面的仿射变换
    目录平面的仿射变换定义放缩变换重要性质点与向量的仿射变换仿射标架的仿射变换变积系数平面的定向平行四边形的仿射变换前后定向面积的特性变积系数及其特性参考平面的仿射变换定义定义平面的一个点变换τ,如果它在一个仿射坐标系中的公式为\[\begin{pmatrix}x'\\y'\end{p......
  • 【编译原理】用C/C++编写一个LL(1)解析器
    任务描述本关任务:用C/C++编写一个LL(1)解析器相关知识为了完成本关任务,你需要掌握:LL文法C/C++编程语言基础C语言的基本结构知识LL(1)解析器在创建解析器之前,你应该创建一个下面文法的LL(1)分析表。C/C++本实训涉及函数、结构体,标准流输入输出,字符串等操作实验要求......