【设计模式深度剖析】【3】【创建型】【抽象工厂模式】| 要和【工厂方法模式】对比加深理解

news2024/11/17 13:26:42

👈️上一篇:工厂方法模式    |   下一篇:建造者模式👉️

目录

  • 抽象工厂模式
    • 前言
    • 概览
    • 定义
      • 英文原话
      • 直译
      • 什么意思呢?(以运动型车族工厂,生产汽车、摩托产品为例)
    • 类图
    • 4个角色
      • 抽象工厂(Abstract Factory)角色
      • 具体工厂(Concrete Factory)角色
      • 抽象产品(Abstract Product)角色
      • 具体产品(Concrete Product)角色
    • 代码说明
      • 1. 抽象工厂类:AbstractFactory.java 接口类
      • 2. 具体工厂类:
        • 2.1 产品族1的具体工厂类:ConcreteFactoryFamily1.java
        • 2.2 产品族2的具体工厂类:ConcreteFactoryFamily2.java
      • 3. 抽象产品A类:ProductA.java
      • 4. A类产品具体产品类:
        • 4.1 产品族为1的A具体产品类:ProductA1.java
        • 4.2 产品族为2的A具体产品类:ProductA2.java
      • 5. 抽象产品B类:ProductB.java
      • 6. B类产品具体产品类:
        • 6.1 产品族为1的B具体产品类:ProductB1.java
        • 6.2 产品族为2的B具体产品类:ProductB2.java
      • 7. 测试类
    • 应用
      • 优点
      • 缺点
        • 情景思考,加深理解:
      • 使用场景

抽象工厂模式

前言

当一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。(多个产品族1,2,3,产品族4… ,每个产品族都有A、B、C等等产品),

如果产品族中只有一种产品,则抽象工厂模式就退化为工厂方法模式

和上一篇【设计模式深度剖析】【2】【创建型】【工厂方法模式】 对比理解,加深理解

上一篇【设计模式深度剖析】【2】【创建型】【工厂方法模式】中提到:

工厂方法模式只能针对一个产品等级结构如A产品B产品。

但是如果是A产品与B产品的第一等级、第二等级,这种情况要抽象工厂模式

也就是它(抽象工厂模式)解决的问题是:多个产品族,多种产品。

多个产品族,每个产品族下又有多种产品——使用抽象工厂模式;

而,仅仅生产某种产品——使用工厂方法模式。


抽象工厂模式(Abstract Factory Pattern)是一种比较常用的模式

抽象工厂模式是工厂方法模式的升级版本。在有多个业务品种、业务分类时,

通过抽象工厂模式产生需要的对象是一种非常好的解决方式。

======== 本文代码示例 ========

概览

  • 定义
  • 4个角色
  • 应用
    • 优点
    • 缺点
    • 使用场景

定义

英文原话

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

直译

意思是:提供一个接口,用于创建相关或依赖的对象族,而无需指定它们的具体类。

什么意思呢?(以运动型车族工厂,生产汽车、摩托产品为例)

这句话描述了一个设计模式的概念,特别是抽象工厂模式(Abstract Factory Pattern)。抽象工厂模式是一种创建型设计模式,它提供了一种方式来封装一组具有共同主题的单独的工厂接口,而无需指定它们的具体类。

简单来说,假设你有两个或更多的产品族(例如,汽车和摩托车),并且每个产品族中都有多种类型的对象(例如,汽车有跑车、SUV等;摩托车有越野车、街车等)

你可能想要一个系统,该系统能够基于一些配置或条件来生成这些产品,但你不希望直接依赖于具体的实现类

抽象工厂模式允许你定义一个接口(抽象工厂),该接口中包含了创建多个产品的方法(每个方法对应于一个产品族中的一个产品类型)。然后,你可以为每种产品族实现这个抽象工厂接口,从而创建具体的产品对象

以下是一个简化的抽象工厂模式的例子:

// 抽象工厂接口-车辆工厂,能生产两种产品-汽车和摩托  
public interface VehicleFactory {  
    Car createCar();  
    Motorcycle createMotorcycle();  
}  
  
// 抽象产品接口-汽车接口  
public interface Car {  
    // ... Car specific methods  
}  
  
// 抽象产品接口-摩托接口
public interface Motorcycle {  
    // ... Motorcycle specific methods  
}  

  
// 具体的产品类(例如,其中一个产品族-运动型车辆族:运动型车辆和运动型摩托车)  
// ... 省略具体实现  
  
  
// 具体工厂类 - 对应于一个产品族,运动型车辆,可以生产运动型汽车、运动型摩托车  
public class SportsCarFactory implements VehicleFactory {  
    @Override  
    public Car createCar() {  
        return new SportsCar(); // 假设这是具体的运动型汽车  
    }  
  
    @Override  
    public Motorcycle createMotorcycle() {  
        return new SportsMotorcycle(); // 假设这是具体的运动型摩托车  
    }  
}  

// 客户端代码  
public class Client {  
    public static void main(String[] args) {  
        VehicleFactory factory = new SportsCarFactory();  
        Car car = factory.createCar();  
        Motorcycle motorcycle = factory.createMotorcycle();  
        // ... 使用car和motorcycle  
    }  
}

在这个例子中,

VehicleFactory 是一个抽象工厂接口,它定义了两个方法(createCarcreateMotorcycle)来创建产品。

SportsCarFactory 是一个具体工厂类**(用于同一产品族[运动型族]的不同类型产品[汽车、摩托车])**,它实现了 VehicleFactory(抽象工厂) 接口,并提供了具体的产品实现(SportsCarSportsMotorcycle)。

客户端代码使用 SportsCarFactory 来创建和使用 CarMotorcycle 对象,而无需直接依赖于具体的实现类

类图

抽象工厂模式类图(本示例程序uml)

4个角色

4个角色与工厂方法模式类似:

抽象工厂(Abstract Factory)角色

该角色是抽象工厂模式的核心,与应用系统无关,任何创建对象的工厂类必须实现这个接口。

具体工厂(Concrete Factory)角色

该角色实现了抽象工厂接口,含有选择合适的产品对象的逻辑,并且受到应用程序的调用以创建产品对象。

抽象产品(Abstract Product)角色

该角色负责定义产品的共性,实现对产品最抽象的定义。

具体产品(Concrete Product)角色

该角色实现抽象产品角色所声明的接口**,抽象工厂模式所创建的任何产品对象都是某个具体产品角色的实例。

代码说明

代码示例

1. 抽象工厂类:AbstractFactory.java 接口类

package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;

/**
 * 抽象工厂接口:声明有两种产品A与B,定义工厂方法,返回产品A与B
 *
 * @author Polaris 2024/5/16
 */
public interface AbstractFactory {
    //创建产品A
    ProductA factoryA();

    //创建产品B
    ProductB factoryB();
}

2. 具体工厂类:

2.1 产品族1的具体工厂类:ConcreteFactoryFamily1.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;

/**
 * 具体工厂类1:实现了抽象工厂接口,生产产品族为1的A产品与B产品。
 *
 * @author Polaris 2024/5/16
 */
public class ConcreteFactoryFamily1 implements AbstractFactory {

    //创建产品族为1的产品A
    @Override
    public ProductA factoryA() {
        return new ProductA1();
    }

    //创建产品族为1的产品B
    @Override
    public ProductB factoryB() {
        return new ProductB1();
    }
}
2.2 产品族2的具体工厂类:ConcreteFactoryFamily2.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;

/**
 * 具体工厂类2:实现了抽象工厂接口,生产产品族为2的A产品与B产品。
 *
 * @author Polaris 2024/5/16
 */
public class ConcreteFactoryFamily2 implements AbstractFactory {
    //创建产品族为2的产品A
    @Override
    public ProductA factoryA() {
        return new ProductA2();
    }

    //创建产品族为2的产品B
    @Override
    public ProductB factoryB() {
        return new ProductB2();
    }
}

3. 抽象产品A类:ProductA.java

package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;

/**
 * 抽象产品A:抽象产品接口,声明了产品A的方法名称、返回类型
 *
 * @author Polaris 2024/5/16
 */
public interface ProductA {
    //产品A的公共方法
    void method1();

    void method2();
}

4. A类产品具体产品类:

4.1 产品族为1的A具体产品类:ProductA1.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;

/**
 * 具体产品A1:实现了抽象产品A接口
 * 产品族为1的A产品
 *
 * @author Polaris 2024/5/16
 */
public class ProductA1 implements ProductA {

    @Override
    public void method1() {
        System.out.println("产品族为1的产品A的实现方法");
    }

    @Override
    public void method2() {
        //业务逻辑代码
    }
}
4.2 产品族为2的A具体产品类:ProductA2.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;

/**
 * 具体产品A2:实现了抽象产品A接口
 * 产品族为2的A产品
 *
 * @author Polaris 2024/5/16
 */
public class ProductA2 implements ProductA {

    @Override
    public void method1() {
        System.out.println("等级为2的产品A的实现方法");
    }

    @Override
    public void method2() {
        //业务逻辑代码
    }
}

5. 抽象产品B类:ProductB.java

package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;

/**
 * 抽象产品B:抽象产品接口,声明了产品B的方法名称、返回类型
 *
 * @author Polaris 2024/5/16
 */
public interface ProductB {
    //产品B的公共方法
    void method1();

    void method2();
}

6. B类产品具体产品类:

6.1 产品族为1的B具体产品类:ProductB1.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;

/**
 * 具体产品B1:实现了抽象产品B接口
 * 产品族为1的B产品
 *
 * @author Polaris 2024/5/16
 */
public class ProductB1 implements ProductB {

    @Override
    public void method1() {
        System.out.println("等级为1的产品B的实现方法");
    }

    @Override
    public void method2() {
        //业务逻辑代码
    }
}
6.2 产品族为2的B具体产品类:ProductB2.java
package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;

/**
 * 具体产品B2:实现了抽象产品B接口
 * 产品族为2的B产品
 *
 * @author Polaris 2024/5/16
 */
public class ProductB2 implements ProductB {

    @Override
    public void method1() {
        System.out.println("等级为2的产品B的实现方法");
    }

    @Override
    public void method2() {
        //业务逻辑代码
    }
}

7. 测试类

  • 抽象工厂类,规定了要生产A产品和B产品(接口就是用来定标准,规范标准的,具体到这里就是规定用来生产A产品和B产品)至于怎么生产,由具体工厂类去实现;

  • 它的引用指向一个具体工厂类-生产产品族为1的具体工厂类的实例;

  • 该产品族工厂-具体工厂,可以生产A和B产品,即1族的A与B产品,即A1, B1产品

  • 生产出的A1, A2实例可以执行业务逻辑,

同理,生产产品族为2的产品A和产品B,即A2, B2,也是一样的。

package com.polaris.designpattern.list1.creational.pattern3.abstractfactory;

/**
 * 测试类
 * @author Polaris 2024/5/16
 */
public class ClientDemo {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactoryFamily1();
        //生产产品族为1的产品A
        ProductA a1 = factory1.factoryA();
        //生产产品族为1的产品B
        ProductB b1 = factory1.factoryB();
        //执行业务逻辑
        a1.method1();
        b1.method1();
        
        
        AbstractFactory factory2 = new ConcreteFactoryFamily2();
        //生产产品族为2的产品A
        ProductA a2 = factory2.factoryA();
        //生产等级为1的产品B
        ProductB b2 = factory2.factoryB();
        //执行业务逻辑
        a2.method1();
        b2.method1();
    }
}

应用

优点

抽象工厂模式工厂方法模式的进一步抽象针对的是一族产品如果产品族中只有一种产品,则抽象工厂模式就退化为工厂方法模式。除了工厂方法模式的优点外,抽象工厂模式还具有下列优点。

  • 产品族内的约束为非公开状态,在不同的工厂中,各种产品可能具有不同的相互依赖关系,这些依赖关系由工厂封装在其内部,对于工厂的使用者是不可见的。
  • 生产线扩展非常容易,如果要针对同一产品族建立新的生产线,只需要 实现 产品族中的所有产品接口建立新的工厂类即可
    • ProductA与ProductB就是产品族(类),即A族产品与B族产品;
    • ProductA1与ProductA2(或ProductB1与ProductB2)就是A族产品(或B族产品)产品族下不同产品线
    • 如A类产品再加一条产品线(族)生产ProductA3(产品族为3的A产品),则需要ProductA3实现ProductA接口方法 ,由于抽象工厂已经定义了A组产品的约束(生产A产品对象的方法),所以对抽象工厂无需改动;但是,每条产品线的产品都需要一个具体工厂类创建对象,因此需要添加一个具体工厂(ConcreteFactoryFamily3)生产新增加的产品线产品A3

缺点

抽象工厂模式的最大缺点就是产品族本身的扩展非常困难,如果需要在产品族中增加一个新的产品类型,则需要修改多个接口并且会影响已有的工厂类

* 抽象工厂声明的方法针对所有产品族产品;
* 新增加一个产品族(C类产品),抽象工厂需要添加生产新产品族产品的接口(声明方法);
* 具体工厂是要实现抽象工厂所有接口的,所以相应的具体工厂(所有各个产品线)需要修改(实现创建新增C产品族产品的方法)
情景思考,加深理解:
  • 比如此示例:两个产品族(即2个种类产品),两条产品线(分别生产1等级与2等级产品)
  • 若:仅仅增加一个产品C(现有产品线都生产这个新增产品类型):
    • 创建产品族C接口,并增加C1/C2产品类实现C类接口
    • 抽象工厂添加创建此类型产品的接口;
    • 所有产品线(具体工厂,某一族)都增加实现接口的方法;
  • 若:现在增加一个产品(即增加1个新产品类型C),但是只生产最高等级(即产品线只有一条(产品线1,产品族1)来生产此产品族产品C),该怎么办?
    • 抽象工厂抽象了各类产品的生产,其他产品线(生产某一族产品)也要实现该族产品生产的接口(方法),但是,不需要创建出相应对象(产品)(因为其余产品线不生产新增产品族产品),可以抛出异常
  • 若:新增产品C,且单独用额外的产品线3生产此族产品(即新产品类型,新开辟产品线专门只用于生产此族产品),该怎么弄?
    • 如上个问题,新增产品族,抽象工厂必定添加接口方法用于生产此产品,现有产品线都要实现这个接口(但是根据需求生产不出来,抛出异常);
    • 新开辟的产品线由于抽象工厂的约束,它要实现生产所有产品族(包括新增产品族)的接口,这条产品线只需要生产新增产品族,生产其他已有产品族产品时抛出异常即可。
  • 所以,新增产品族比较麻烦,涉及到新增产品C接口及具体产品线产品,以及抽象工厂、具体工厂的变动,这是个很大的变动。即:产品族本身的扩展非常困难

使用场景

抽象工厂模式的使用场景是:一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。

抽象工厂模式是一个简单的模式,使用的场景非常多,

例如,应用需要涉及不同操作系统的时候,可以考虑使用抽象工厂模式,如果需要在三个不同的平台(Windows、Linux、Android)上运行,则可以通过抽象工厂模式屏蔽掉操作系统对应用的影响。三个不同操作系统上的软件功能、应用逻辑、UI都应该是非常类似的,唯一不同的是调用不同的工厂方法,由不同的产品类去处理与操作系统交互的信息。

👈️上一篇:工厂方法模式    |   下一篇:建造者模式👉️

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

美业系统源码美业SaaS系统-门店卡项已线下退款,需要作废怎么处理?

美业SaaS系统源码 连锁门店美业收银系统源码 收银管理 / 会员管理 / 预约管理 / 排班管理 / 商品管理 / 活动促销 PC管理后台、手机APP、iPad APP、微信小程序 1、加盟店卡项线下退款处理方法: 询问具体退款会员手机号和卡项,找到需要退款的订单号。…

jenkins自动化部署详解

一、准备相关软件 整个自动化部署的过程就是从git仓库拉取最新代码,然后使用maven进行构建代码,构建包构建好了之后,通过ssh发送到发布服务的linux服务器的目录,最后在此服务器上执行相关的linux命令进行发布。 此篇文章jenkins…

优思学院|六西格玛在人力资源管理(HR)的应用指南

有效的HR流程管理对于组织的成功至关重要。然而,许多组织在HR效率方面存在困难,导致员工流动率高、工作放弃率高、生产力低下、缺勤率高以及盈利能力下降。 六西格玛方法论可以用来识别改进领域并实施变革,从而使HR功能更加高效和有效。 这…

监控上网的软件有哪些?含泪推荐的电脑监控软件

监控上网的软件有很多,企业选择的时候应该遵循什么样的原则呢?鄙人愚见,认为以下四项原则是选择监控软件时首要考虑的。 1、功能需求: 监控软件不应该只是起到控制上网的作用,因为一些泄密行为可能是通过USB接口、打印…

TI C2000 FLASH 模拟 EEPROM

简述 FLASH和EEPROM同为非易失存储器,互有优势。 FLASH Flash是非易失性存储器(NVM)的一种形式。相对于EEPROM,Flash具有更高的存储密度和更快的写入速度。Flash内部被分为多个扇区,每个扇区都可以单独擦除和写入。但是寿命相比EEPROM较短,以TI芯片为例,flash擦写次数在…

Linux下的权限

目录 1.shell命令以及运行原理 1.1原理上初步理解shell外壳 1.1.1为什么要有shell外壳 1.1.2shell外壳是什么 1.1.3怎么办(shell外壳的基本运行原理) 2.Linux下的用户 3.Linux权限管理 3.1.文件访问者的分类(人) 3.2…

社交媒体数据恢复:LinkdIn

在我们的日常工作中,数据丢失是一个非常棘手的问题。但是,如果你懂得如何进行数据恢复,那么这个问题就不再那么可怕了。本文将为您提供一份详细的LinkedIn数据恢复教程,帮助您找回丢失的数据。 首先,我们需要了解为什…

谷粒商城环境准备~下 docker版

10. 配置中心 1&#xff09;修改“gulimall-coupon”模块 添加pom依赖&#xff1a; <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>创建bootstr…

C++设计模式---面向对象原则

面向对象设计原则 原则的目的&#xff1a;高内聚&#xff0c;低耦合 1. 单一职责原则 类的职责单一&#xff0c;对外只提供一种功能&#xff0c;而引起类变化的原因都应该只有一个。 2. 开闭原则 对扩展开放&#xff0c;对修改关闭&#xff1b;增加功能是通过增加代码来实现的&…

10G SFP双口万兆以太网控制器,高速光口网络接口卡

2-Port 10G SFP NIC 是一款高速网 络接口卡&#xff0c;采用了 PCI Express 3.0 x8 接口&#xff0c;支持双 端口万兆以太网&#xff0c;具有高性能、高可靠性、低功耗等 优点&#xff0c;是数据中心、云计算、虚拟化等领域的理想选 择。 支持多种网络协议&#xff0c;如 …

不懂平面设计,这篇文章教你制作商业画册

​商业画册不仅是企业展示形象、推广产品的重要工具&#xff0c;也是设计师展现创意的平台。因此&#xff0c;制作一本高质量的画册对于企业来说至关重要。 那要怎么着手制作呢&#xff1f;以下是关于制作商业画册的步骤。 1.要制作电子杂志,首先需要选择一款适合自己的软件。…

从失败开始浅谈如何交易现货白银

投资者进入现货白银市场&#xff0c;可以说目的就是在这个市场中盈利&#xff0c;只有极少数朋友是想在这个市场中冒险&#xff0c;体验一下资金盈亏所带来的刺激。然而&#xff0c;投资者在交易现货白银的时候&#xff0c;由于一心想获利&#xff0c;因此他们很怕谈失败&#…

Python学习---基于进程池的文件夹copy器案例

# 思路&#xff1a; # 1、定义变量&#xff0c;保存源文件和目标文件夹的路径 # 2、在目标路径创建新的文件夹 # 3、获取源文件夹中的所有文件&#xff08;列表&#xff09; # 4、遍历列表得到所有文件名 # 5、定义函数进行文件拷贝 # 文件拷贝函数&#xff1a; # 参数&#xf…

基于manifest文件批量将coding的仓库导入gitlab中

文章目录 写在前面的话背景编写manifest文件最终效果 写在前面的话 前面有讲过通过manifest清单导入项目到gitlab中&#xff0c;但是实际的操作是不同gitlab实例之间的操作&#xff0c;然而对于在不同gitlab实例的repo迁移而言&#xff0c;显然direct transfer会更合适。 背景…

房地产画册制作成手机在线翻页效果

​随着科技的飞速发展&#xff0c;移动互联网已经深入到人们的日常生活中。在这个数字化的时代&#xff0c;房地产行业也紧跟潮流&#xff0c;将画册制作成手机在线翻页效果&#xff0c;以满足消费者的阅读习惯。 房地产画册制作成手机在线翻页效果&#xff0c;不仅能够满足消费…

Win10【无线显示器】安装失败(无法添加)解决中。。。

目录 ■失败现象 ■解决方法 【服务启动1】 【服务确认】 【服务启动2】 参考 ■查看电脑是否支持【Miracast无线投屏功能】 参考2 ■解决方法&#xff08;对我的这台电脑有效&#xff09; ■解决后的效果 ■连接时&#xff0c;出现【无法在此设备上查看受保护内容。…

时空扭曲:重温相对论的终极挑战,探寻真理的脚步

大家都知道&#xff0c;相对论是爱因斯坦提出的划时代理论&#xff0c;为人类认知时空和引力做出了革命性贡献。但这个理论真的万无一失吗&#xff1f;近日&#xff0c;一项新研究提出了测试时间扭曲的新方法&#xff0c;或许能让我们重新审视相对论在宇宙大尺度上的适用性。 时…

安卓高级控件(下拉框、列表类视图、翻页类视图、碎片Fragment)

下拉框 此小节介绍下拉框的用法以及适配器的基本概念&#xff0c;结合对下拉框Spinner的使用说明分别阐述数组适配器ArrayAdapter、简单适配器SimpleAdapter的具体用法与展示效果。 下拉框控件Spinner Spinner是下拉框控件&#xff0c;它用于从一串列表中选择某项&#xff0…

时代终结,微软宣布淘汰VBScript;Flink漏洞被广泛利用;Grandoreiro银行木马强势回归,1500多家银行成攻击目标 | 安全周报0524

揭秘SolarMarker恶意软件&#xff1a;多层次基础设施让清除工作陷入困境 Recorded Future的新发现表明&#xff0c;SolarMarker信息窃取恶意软件背后的持续威胁行为者已经建立了一个多层次的基础设施&#xff0c;以使执法部门的清除工作变得复杂。 该公司在上周发布的一份报告…