探索设计模式的魅力:抽象工厂模式的艺术

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,用于在不指定具体类的情况下创建一系列相关或相互依赖的对象。它提供了一个接口,用于创建一系列“家族”相关依赖对象,而无需指定它们的具体类。

        

主要参与者:

  1. 抽象工厂(Abstract Factory):提供一个接口,用于创建一些相关或相互依赖的对象家族,而不需要指定它们具体的类。
  2. 具体工厂(Concrete Factory):实现抽象工厂的操作以生产具体的产品对象。
  3. 抽象产品(Abstract Product):为一系列产品对象声明一个接口。
  4. 具体产品(Concrete Product):抽象产品的子类,定义用于生产的具体产品对象。
  5. 客户(Client):仅使用由抽象工厂和抽象产品类声明的接口。

实现步骤:

  1. 定义抽象产品,确定产品家族中的不同产品。
  2. 创建抽象工厂类,定义创建抽象产品的接口。
  3. 实现具体工厂类,每个工厂类负责创建不同的产品变体。
  4. 客户端代码通过抽象工厂和抽象产品类接口与工厂和产品交互。

优势:

  • 隔离具体类的生成:客户端不需要知道它所使用的对象的具体类,只需要关心所使用对象的接口。
  • 易于交换产品系列:因为具体的工厂类都派生自同一个抽象类,可以很容易地更换使用的工厂类来切换整个产品系列。
  • 增强一致性:产品在一系列中一致地创建,这保证了客户端始终只使用同一产品系列中的对象。

缺点:

  • 难以支持新种类的产品:如果需要添加额外的产品到系列中,抽象工厂和所有具体工厂类都需要改变,这违反了开闭原则。

探索设计模式的魅力:简单工厂模式-CSDN博客文章浏览阅读2.5k次,点赞58次,收藏46次。实现简单工厂的难点就在于 “如何选择” 实现,前面便子中传递参数的方法, 那都是静态的参数,还可以实现成为动态的参数。客户端通过简单工厂创建 了一个实现接口的对象,然后面向接口编程,从客户端来看,它根本不知道具体的实现是什么,也不知道是如何实现的,它只知道通过工厂获得了一个接口对象 , 然后通过这个接口来获取想要的功能。如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能理解各个参数所代表的具体功能和含义,这样会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以选用可配置的方式来实现。https://blog.csdn.net/danci_/article/details/135566105探索设计模式的魅力:工厂方法模式-CSDN博客文章浏览阅读2.5k次,点赞83次,收藏47次。工厂方法模式是一种创建型设计模式,它提供了一种创建对象的接口,但将具体实例化对象的工作推迟到子类中完成。这样做的目的是创建对象时不用依赖于具体的类,而是依赖于抽象,这提高了系统的灵活性和可扩展性。优点:降低耦合度、增加了系统的可扩展性 和 提高代码的可维护性;缺点:增加了代码的复杂性 和 需要更多的设计考虑。https://blog.csdn.net/danci_/article/details/135611783

目录

一、案例

1.1 示例代码

  1.1.1 简单工厂实现

  1.1.2 问题        

  1.1.3 抽象工厂实现

二、模式讲解

 2.1 功能

 2.2 抽象工厂模式的结构及说明

 2.3 示例代码程序结构图

 2.4 抽象工厂模式与简单工厂模式

 2.5 抽象工厂模式与工厂方法模式


一、案例

        场景:造一辆汽车(买零件来组装),汽车有很多的零组成,成百上千个零件相互依赖配合工作,比如发动机和变速箱。

        选择零件时,每个零件的品牌、规格 等如何才能选择到合适的搭配才能配合正常工作,也就是说汽车是一个整体,每个零件之间有关联的。

1.1 示例代码

        汽车零件有成百上升个,这里只举例发动机和变速箱。市面上有各种品牌的发动机和变速箱,同一品牌还有各种型等,这里举两个。

  1.1.1 简单工厂实现

         发动机接口:

public interface EngineApi {void run();
}

        变速箱接口:

public interface GearboxApi {void run();
}

        林肯发动机和林肯变速箱:

public class LinkenEngineApiImpl implements EngineApi {@Overridepublic void run() {System.out.println("林肯发动机工作了");}
}public class LinkenGearboxApiImpl implements GearboxApi {@Overridepublic void run() {System.out.println("林肯变速箱工作了");}
}

        丰田发动机和丰田变速箱:

public class ToyotaEngineApiImpl implements EngineApi {@Overridepublic void run() {System.out.println("丰田发动机工作了");}
}public class ToyotaGearboxApiImpl implements GearboxApi {@Overridepublic void run() {System.out.println("丰田变速箱工作了");}
}

        发动机工厂:

public class EngineFactory {public static EngineApi getEngineApi(int i) {if (i == 1) {return new LinkenEngineApiImpl();}return new ToyotaEngineApiImpl();}
}

        变速箱工厂 :

public class GearboxFactory {public static GearboxApi getGearbox(int i) {if (1 == i) {return new LinkenGearboxApiImpl();}return new ToyotaGearboxApiImpl();}
}

        汽车组装类:

public class CarEngineer {public void makeCar(int engineType, int gearboxType) {EngineApi engineApi = EngineFactory.getEngineApi(engineType);GearboxApi gearbox = GearboxFactory.getGearbox(gearboxType);engineApi.run();gearbox.run();}
}

        客户端:

public class CarClient {public static void main(String[] args) {CarEngineer carEngineer = new CarEngineer();carEngineer.makeCar(1, 1);}
}

        运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_311.jdk/...
林肯发动机工作了
林肯变速箱工作了

        修改客户端carEngineer.makeCar(1, 2); 运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_311.jdk/...
林肯发动机工作了
丰田变速箱工作了

  1.1.2 问题        

        修改了产数之后,组装的汽车使用了林肯的发动机,而变速箱是丰田的,此时发动机与变速箱不是一个品牌,如果发动机与变速箱不匹配无法正常配合工作,那么组装的这个汽车就等于废了(这里假设只有同品牌的零部件才能正常配合动作)。

        显然发动机与变速箱是需要互相匹配,强依赖关系。就是选了这个发动机就必须选定某个变速箱。抽象工厂来解决这个问题。

        

  1.1.3 抽象工厂实现

抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接又,而无需指定它们具体的类。

        解决1.1.2问题是要创建一序列有相互依赖关联和相互约束的产品——抽象工厂模式。

        代码改造

        发动机接口和变速箱接口不变:

public interface EngineApi {void run();
}
public interface GearboxApi {void run();
}

        发动机和变速箱的实现也不变:

public class LinkenEngineApiImpl implements EngineApi {@Overridepublic void run() {System.out.println("林肯发动机工作了");}
}public class LinkenGearboxApiImpl implements GearboxApi {@Overridepublic void run() {System.out.println("林肯变速箱工作了");}
}public class ToyotaEngineApiImpl implements EngineApi {@Overridepublic void run() {System.out.println("丰田发动机工作了");}
}public class ToyotaGearboxApiImpl implements GearboxApi {@Overridepublic void run() {System.out.println("丰田变速箱工作了");}
}

        添加抽象工厂:(工厂抽象出来)

public interface AbstractFactory {/*** 创建发动机 <br/>*/EngineApi createLinken();/*** 创建变速箱 <br/>*/GearboxApi createGearbox();
}

        发动机工厂修改为林肯工厂,并实现抽象工厂:(//注释部分为简单工厂代码)

public class LinkenFactory implements AbstractFactory {
//public class EngineFactory {/*** 生产林肯发动机*/@Overridepublic EngineApi createLinken() {return new LinkenEngineApiImpl();}/*** 生产林肯发变速箱*/@Overridepublic GearboxApi createGearbox() {return new LinkenGearboxApiImpl();}//public static EngineApi getEngineApi(int i) {//    if (i == 1) {//        return new LinkenEngineApiImpl();//    }////    return new ToyotaEngineApiImpl();//}
}

        变速箱工厂修改为丰田工厂,并实现抽象工厂:(//注释部分为简单工厂代码)

public class ToyotaFactory implements AbstractFactory {
//public class GearboxFactory {/*** 生产丰田发动机*/@Overridepublic EngineApi createLinken() {return new ToyotaEngineApiImpl();}/*** 生产丰田变事箱*/@Overridepublic GearboxApi createGearbox() {return new ToyotaGearboxApiImpl();}//public static GearboxApi getGearbox(int i) {//    if (1 == i) {//        return new LinkenGearboxApiImpl();//    }////    return new ToyotaGearboxApiImpl();//}
}

         汽车组装类有修改:(//注释部分为简单工厂代码)

public class CarEngineer {/*** 接收选择好的哪一个序列产品工厂* @param factory*/public void makeCar(AbstractFactory factory) {EngineApi engineApi = factory.createLinken();GearboxApi gearbox = factory.createGearbox();engineApi.run();gearbox.run();}//public void makeCar(int engineType, int gearboxType) {//    EngineApi engineApi = EngineFactory.getEngineApi(engineType);//    GearboxApi gearbox = GearboxFactory.getGearbox(gearboxType);//    engineApi.run();//    gearbox.run();//}
}

        客户端:(//注释部分为简单工厂代码)

public class CarClient {public static void main(String[] args) {//CarEngineer carEngineer = new CarEngineer();//carEngineer.makeCar(1, 2);CarEngineer carEngineer = new CarEngineer();// 传入选中的哪种产品工厂carEngineer.makeCar(new LinkenFactory());}
}

        运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_311.jdk/...
林肯发动机工作了
林肯变速箱工作了

        修改选中的产品工厂carEngineer.makeCar(new ToyotaFactory()) ,运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_311.jdk/...
丰田发动机工作了
丰田变速箱工作了

        这个抽象工厂相当于选择一套方案,方案确定好,里面的零件也就确定好了。不用一个零件一个零件的选择以免选择出错

        

二、模式讲解

 2.1 功能

功能: 为一系列相关对象或相互依赖的对象创建一个接口。

接口内的方法是一系列相互依赖和约束的方法。

        

 2.2 抽象工厂模式的结构及说明

  • AbstractFactory:抽象工厂,定义创建一系列产品对象的操作接口。

  • FactoryA:具体的工厂,实现抽象工厂定义的方法,具体实现一系列产品对象的创建。

  • AbstractProduct:定义类产品对象的接口。

  • ProductA:具体的产品实现对象,通常在具体工厂里面,会选择具体的产品实现对象,来创建符合抽象工厂定义的方法返回的产品类型的对象。

  • Client:客户端,主要使用抽象工厂来获取一系列所需要的产品对象,然后面向这些产品对象的接口编程,以实现需要的功能。

        

 2.3 示例代码程序结构图

        抽象工厂模式主要用于以下几个方面的应用场景中:

  1. 需要创建一系列相互依赖的对象:当一组对象之间存在依赖关系,并且需要保证这些对象是兼容的,抽象工厂模式可以用来创建这些对象的族群。

  2. 希望实现多个产品族的变化:抽象工厂模式允许你定义多个工厂类,每个工厂类可以创建不同的产品族,从而可以实现对产品族的变化。

  3. 需要切换产品组合:通过使用抽象工厂模式,可以很方便地切换不同的产品组合,而无需修改已有的客户端代码。

        优势方面,抽象工厂模式具有以下几个优势:

  1. 封装了对象的创建过程:客户端只需关注抽象工厂类和抽象产品类,而无需关心具体的创建细节,将对象创建的过程封装在工厂类中,提供了更高的封装性和抽象性。

  2. 符合开闭原则:抽象工厂模式对于新增新的产品族非常方便,只需创建对应的新的工厂类即可,并且不需要修改已有的代码,符合开闭原则。

  3. 保持产品族的一致性:通过抽象工厂模式创建的产品族中的产品具有一定的约束关系,保证了产品的一致性,避免了不兼容的产品组合。

        

 2.4 抽象工厂模式与简单工厂模式

        抽象工厂模式和简单工厂模式是两种常见的设计模式,它们在对象的创建和管理上有一些不同之处。

  1. 目的和应用场景:

  • 简单工厂模式(Simple Factory Pattern)旨在根据给定的参数来创建单一类型的对象实例。它适用于需要根据条件创建不同类型的对象的情况,但它并没有分离对象的创建和使用,违反了单一职责原则。
  • 抽象工厂模式(Abstract Factory Pattern)旨在创建一系列相关或相互依赖的对象,而无需显式指定其具体类。它适用于需要创建一组相关的产品对象,并且需要确保这些产品是兼容的情况。

  2. 结构与实现:

  • 简单工厂模式通常由一个工厂类通过静态方法来创建对象,客户端通过调用工厂类的方法并传入相应的参数来获得所需的对象。
  • 抽象工厂模式通常由一组抽象工厂和一组具体工厂类组成,每个具体工厂负责创建一组特定的产品。

  3. 灵活性与扩展性:

  • 简单工厂模式的灵活性相对较低,因为一旦需要添加新类型的产品,通常需要修改工厂类的静态方法。
  • 抽象工厂模式支持产品族的概念,可以非常容易地添加新的产品族,只需要新增对应的具体工厂类即可,而不需要修改客户端代码。

总的来说,简单工厂模式适用于需要创建单一类型的对象,并且可以根据条件动态地创建不同类型的对象。而抽象工厂模式适用于创建一系列相关或相互依赖的对象,并且需要确保这些对象是兼容的情况。在实际应用中,根据具体的需求和设计目标来选择合适的设计模式。

        

 2.5 抽象工厂模式与工厂方法模式

        抽象工厂模式(Abstract Factory Pattern)和工厂方法模式(Factory Method Pattern)虽然同属于创建型设计模式,旨在解耦对象的创建和使用,但两者在目的、实现方式及应用场景上存在明显区别:

  1. 目的:

  • 工厂方法模式的目的是允许一个类在不知道将要创建的对象的具体类型的情况下,推迟其实例化到子类中进行。
  • 抽象工厂模式的目的是创建一系列相关或者相互依赖的对象,而不需要指定它们具体的类。

  2. 实现方式:

  • 工厂方法模式定义了一个用于创建对象的接口,但由子类决定实例化哪一个类。工厂方法让类的实例化推迟到子类中进行。
  • 抽象工厂模式提供了一个创建一系列相关或互相依赖对象的接口,而不需要指定它们具体的类。它通常包含多个工厂方法来创建一系列不同的产品。

  3. 应用场景:

  • 工厂方法模式主要用于单一产品的创建情形,即客户端只需要一个产品,而具体哪个产品则由具体工厂类在运行时决定。
  • 抽象工厂模式适用于创建一组产品(产品族),这些产品设计成合作使用的,客户端需要多个产品对象,这些对象要按照一定的方式配合工作。

  4. 结构复杂度:

  • 工厂方法模式结构相对简单,每个具体工厂类只需要负责一个产品的创建。
  • 抽象工厂模式结构相对复杂,一个工厂类需要负责多个产品对象的创建,这些对象通常属于不同的类系列。

  5. 扩展难度:

  • 工厂方法模式较容易扩展,引入新的产品类型只需要添加相应的具体工厂类和产品类即可。
  • 抽象工厂模式相对难以扩展,如果需要添加新的产品系列,需修改抽象工厂的接口以及所有的实现类,这会违反开闭原则。

总之,工厂方法模式用于创建一个产品,而抽象工厂模式用于创建多个相互依赖或相互关联的产品族。在选择使用哪一个模式时,需要根据具体场景和设计需求去判断。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/411125.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jest 28发布

Jest 28终于来了&#xff0c;它带来了一些长期以来一直要求的特性&#xff0c;比如支持跨多台机器的测试运行分片、包导出和自定义假计时器行为的能力。 新特性 安装大小减少了大约 1/3 正如在去年的Jest 27博客中所宣布的那样&#xff0c;已经从默认安装中删除了一些不再默…

阿赵UE学习笔记——11、地形系统

阿赵UE学习笔记目录 大家好&#xff0c;我是阿赵。   继续学习虚幻引擎的用法&#xff0c;这次来学习一下虚幻引擎的地形系统的用法。 一、创建地形 在选项模式里面&#xff0c;选择地形&#xff1a; 进入到地形界面之后&#xff0c;需要先创建一个地形&#xff1a; 留意看…

stm32 - GPIO

stm32 - GPIO 基本结构输入输出 基本结构 所有GPIO都挂在APB2总线上 寄存器&#xff1a;内核通过APB2总线对寄存器进行读写&#xff0c;实现电平的读写 GPIO引脚的每一位对应寄存器中的某一位 GPIO中的驱动器是增加信号驱动能力的&#xff0c;用于增大驱动能力 输入 读取端口的…

吃瓜教程Task1:概览西瓜书+南瓜书第1、2章

由于本人之前已经学习过西瓜书&#xff0c;本次学习主要是对以往知识的查漏补缺&#xff0c;因此本博客记录了在学习西瓜书中容易混淆的点以及学习过程中的难点。更多学习内容可以参考下面的链接&#xff1a; 南瓜书的地址&#xff1a;https://github.com/datawhalechina/pumpk…

mobi文件怎么转换成pdf?

mobi文件怎么转换成pdf&#xff1f;在数字化时代&#xff0c;电子书籍成为了越来越受欢迎的阅读方式。我们可以通过多种格式的电子书来获取知识和娱乐&#xff0c;其中一种常见的格式就是Mobi文件。Mobi文件是亚马逊公司开发的一种电子书格式&#xff0c;它主要用于Kindle设备和…

C语言通过MSXML6.0读写XML文件(同时支持char[]和wchar_t[]字符数组)

开发环境&#xff1a;Visual Studio 2010 运行环境&#xff1a;Windows XP SP3 第一节 读取XML文件&#xff08;使用wchar_t[]字符数组&#xff09; /* 这个程序只能在C编译器下编译成功, 请确保源文件的扩展名为c */ #define COBJMACROS #include <stdio.h> #include …

Springboot 子工程构建完后无法找到springboot依赖

问题: 构建完子工程后无法找到SpringBootTest 解决方案: 最好用这个构建 https://www.cnblogs.com/he-wen/p/16735239.html 1.先观察项目目录 是否正确 2.观察子工程目录 3.看pom.xml中是否引用springboot依赖 4.检查代码 查看父项目是否包含子模块 查看子模块的父项目是否…

uniapp写微信小程序实现电子签名

写电子签名一定要注意的是一切全部按照手机上的适配来&#xff0c;为啥这么说呢&#xff0c;因为你在微信开发者工具中调试的时候认为是好的&#xff0c;正常的非常nice,当你发布版本的时候你会发现问题出来了。我下边的写法你可以直接用很简单。就是要记住canvas的几个属性和用…

基于SSM的校园闲置物品交易平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

教师语言的重要性体现在哪些方面?

教师&#xff0c;这个职业被誉为人类灵魂的工程师&#xff0c;他们的话语有着无可比拟的力量。有时&#xff0c;一句话就能点亮一个孩子的世界&#xff0c;也可以打破一个孩子的求知欲望。那么&#xff0c;教师话语的重要性究竟体现在哪些方面呢&#xff1f; 教师的话语是激发…

帮管家 CRM init 信息泄露漏洞

此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xff0c;均由使用…

npm换源

检查现在的源地址 npm config get registry 使用淘宝镜像 npm config set registry https://registry.npm.taobao.org 使用官方镜像 npm config set registry https://registry.npmjs.org/

《WebKit 技术内幕》之三(2): WebKit 架构和模块

2.基于 Blink 的 Chrominum 浏览器结构 2.1 Chrominum 浏览器的架构及模块 Chromium也是基于WebKit&#xff08;Blink&#xff09;开发的&#xff0c;并且在WebKit的移植部分中&#xff0c;Chromium也做了很多有趣的事&#xff0c;所以通过Chromium可以了解如何基于WebKit构建浏…

大数据深度学习ResNet深度残差网络详解:网络结构解读与PyTorch实现教程

文章目录 大数据深度学习ResNet深度残差网络详解&#xff1a;网络结构解读与PyTorch实现教程一、深度残差网络&#xff08;Deep Residual Networks&#xff09;简介深度学习与网络深度的挑战残差学习的提出为什么ResNet有效&#xff1f; 二、深度学习与梯度消失问题梯度消失问题…

高斯Hack算法

背景 刷leetcode时&#xff0c;碰到一题需要求解n个bit中选择m个bit的所有组合集&#xff0c;我只想到了递归求解&#xff0c;没啥问题&#xff0c;但是在官方题解中看到了牛逼的方法(Gospers Hack)&#xff0c;故记录一下。 4bit中2个1的情况 0011b0101b0110b1001b1010b1100b…

力扣刷MySQL-第三弹(详细讲解)

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;力扣刷题讲解-MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出…

Kylin 安装novnc 远程访问

noVNC可以使用浏览器直接访问服务器&#xff0c;而不需要使用VNC客户端。 1.初始环境 关闭防火墙或允许IP访问本机 2.安装依赖 dnf install -y tigervnc-server git 3.git下载novnc git clone https://github.com/novnc/noVNC.git 4.配置信任证书 openssl req -new -x509 …

循环异步调取接口使用数组promiseList保存,Promise.all(promiseList)获取不到数组内容,then()返回空数组

在使用 vue vant2.13.2 技术栈的项目中&#xff0c;因为上传文件的接口是单文件上传&#xff0c;当使用批量上传时&#xff0c;只能循环调取接口&#xff1b;然后有校验内容&#xff1a;需要所有文件上传成功后才能保存&#xff0c;在文件上传不成功时点击保存按钮&#xff0c…

vscode mysql cmake windows 常见问题和推荐文章

1.在windows中安装mingw64和cmake&#xff08;可查一下网上的安装教程&#xff09;&#xff0c;配置环境变量 2.在vscode中用CMake构建项目的时候&#xff0c;可能会出现这样的问题:“The C compiler identification is unknownn...”,可参考这篇博客 在windows下使用Vscode用…

pyspark笔记:over

1 方法介绍 在 PySpark 中&#xff0c;over 函数是一个非常重要的概念&#xff0c;尤其是在使用窗口函数&#xff08;例如 row_number, rank, dense_rank, lead, lag 等&#xff09;时。over 函数允许你对一个数据集进行分组&#xff0c;然后在每个分组内应用窗口函数。 1.1 …