创建型设计模式05-抽象工厂模式

news2024/11/25 2:43:36

✨作者:猫十二懿

❤️‍🔥账号:CSDN 、掘金 、个人博客 、Github

🎉公众号:猫十二懿

抽象工厂模式

1、抽象工厂模式介绍

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,围绕一个超级工厂创建其他工厂,也称作为工厂的工厂(大工厂里的小工厂)。在抽象工厂模式中,接口负责创建一组相关对象的工厂,而不需要显式指定它们的类。这种设计模式能够将客户端与具体的实现分离,从而使得客户端可以在不必知道具体产品的情况下创建多个相关的产品对象

1.1 抽象工厂的结构图

image-20230506112705588

抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。

  1. AbstractFactory:抽象工厂类,定义了一组用于创建产品(ProductA和ProductB)的抽象方法,具体的工厂类将实现这些抽象方法。
  2. ConcreteFactory1和ConcreteFactory2:具体工厂类,实现了AbstractFactory中定义的创建产品的抽象方法。在本例中,ConcreteFactory1用于创建ProductA1和ProductB1的实例,而ConcreteFactory2用于创建ProductA2和ProductB2的实例。
  3. AbstractProductA和AbstractProductB:抽象产品类,定义了产品的通用接口。具体产品类将实现这些接口。
  4. ProductA1、ProductA2、ProductB1和ProductB2:具体产品类,实现了AbstractProductA和AbstractProductB中定义的接口。

当客户端需要创建产品时,它会先创建一个具体的工厂类,然后使用该工厂类创建所需的产品实例。由于抽象工厂提供了一组相关的产品接口,因此这些产品之间具有共同点,可以很方便地进行组合、配对或者交换。而具体工厂则根据客户端的需求,在运行时动态创建产品实例,从而实现了客户端与具体实现之间的解耦。

那下面来看看这个具体的实现吧

1.2 抽象工厂模板实现

抽象产品类:

// 抽象产品类 A
interface AbstractProductA {
  void operationA();
}

// 抽象产品类 B
interface AbstractProductB {
  void operationB();
}

实现不同的抽象产品,产出具体不同的产品:

// 具体产品类 A1
class ProductA1 implements AbstractProductA {
  @Override
  public void operationA() {
    System.out.println("具体产品类 A1 实现抽象产品 A");
  }
}

// 具体产品类 A2
class ProductA2 implements AbstractProductA {
  @Override
  public void operationA() {
    System.out.println("具体产品类 A2 实现抽象产品 A");
  }
}

// 具体产品类 B1
class ProductB1 implements AbstractProductB {
  @Override
  public void operationB() {
    System.out.println("具体产品类 B1 实现抽象产品 B");
  }
}

// 具体产品类 B2
class ProductB2 implements AbstractProductB {
  @Override
  public void operationB() {
    System.out.println("具体产品类 B2 实现抽象产品 B");
  }
}

抽象工厂类:创建产品的类

相当于一个大工厂,里面可以产出很多产品,但是每个产品都属于大工厂里面的一个小工厂,也就是大工厂里面有小工厂,在小工厂里面实现具体的产品

// 抽象工厂类
interface AbstractFactory {
  AbstractProductA createProductA();
  AbstractProductB createProductB();
}

具体的小工厂:

// 具体工厂类 1
class ConcreteFactory1 implements AbstractFactory {
  @Override
  public AbstractProductA createProductA() {
    return new ProductA1();
  }

  @Override
  public AbstractProductB createProductB() {
    return new ProductB1();
  }
}

// 具体工厂类 2
class ConcreteFactory2 implements AbstractFactory {
  @Override
  public AbstractProductA createProductA() {
    return new ProductA2();
  }

  @Override
  public AbstractProductB createProductB() {
    return new ProductB2();
  }
}

客户端实现:

// 客户端
public class Client {
  public static void main(String[] args) {
    // 创建具体工厂类 1
    AbstractFactory factory1 = new ConcreteFactory1();

    // 使用工厂类 1 创建产品 A 和 B
    AbstractProductA productA1 = factory1.createProductA();
    AbstractProductB productB1 = factory1.createProductB();

    // 调用产品 A 和 B 的方法
    productA1.operationA();
    productB1.operationB();

    // 创建具体工厂类 2
    AbstractFactory factory2 = new ConcreteFactory2();

    // 使用工厂类 2 创建产品 A 和 B
    AbstractProductA productA2 = factory2.createProductA();
    AbstractProductB productB2 = factory2.createProductB();

    // 调用产品 A 和 B 的方法
    productA2.operationA();
    productB2.operationB();
  }
}

2、具体例子实现

假设你是一位室内设计师,你需要为客户的房间设计家具。不同的客户有不同的风格和预算,因此你需要选择不同的家具制造商来满足客户的需求。在这种情况下,你可以将抽象工厂模式应用于家具制造业。

首先,你需要定义一个家具抽象工厂接口,它有两个方法:createChair()createSofa(),分别用于创建椅子和沙发。然后,你可以创建多个具体的家具工厂类(例如,现代家具工厂、传统家具工厂等),它们分别实现了家具抽象工厂接口并负责创建不同类型的家具。

最后,你可以根据客户的需求选择相应的家具工厂来创建家具。例如,如果客户需要现代家具,你可以使用现代家具工厂来创建现代风格的椅子和沙发;如果客户需要传统家具,你可以使用传统家具工厂来创建传统风格的椅子和沙发。

这样,抽象工厂模式帮助你解耦了客户和具体的家具制造商,使得你可以更容易地切换不同的制造商,同时也为客户提供了更多的选择。

2.1 不使用抽象工厂模式实现

家具类:

/**
 * @author Shier
 * 家具类
 */
public class Furniture {
    private String type;
    private String style;
    private double price;

    public Furniture(String type, String style, double price) {
        this.type = type;
        this.style = style;
        this.price = price;
    }
    
    public void printInfo() {
        System.out.println("Type: " + type);
        System.out.println("Style: " + style);
        System.out.println("Price: " + price);
    }
}

现代风格类:

/**
 * @author Shier
 * 现代风格家具制造商
 */
public class ModernFurnitureMaker {
    public Furniture createChair() {
        return new Furniture("椅子", "现代风格", 150.0);
    }

    public Furniture createSofa() {
        return new Furniture("沙发", "现代风格", 500.0);
    }
}

传统风格类:

/**
 * @author Shier
 * 传统风格家具制造商
 */
public class TraditionalFurnitureMaker {
    public Furniture createChair() {
        return new Furniture("椅子", "传统风格", 100.0);
    }

    public Furniture createSofa() {
        return new Furniture("沙发", "传统风格", 600.0);
    }
}

客户端类:

/**
 * @author Shier
 * 客户端类
 */
public class Client {
    public static void main(String[] args) {
        // 创建现代风格家具
        ModernFurnitureMaker modernMaker = new ModernFurnitureMaker();
        Furniture modernChair = modernMaker.createChair();
        Furniture modernSofa = modernMaker.createSofa();

        // 打印信息
        modernChair.printInfo();
        modernSofa.printInfo();

        // 创建传统风格家具
        TraditionalFurnitureMaker traditionalMaker = new TraditionalFurnitureMaker();
        Furniture traditionalChair = traditionalMaker.createChair();
        Furniture traditionalSofa = traditionalMaker.createSofa();

        // 打印信息
        traditionalChair.printInfo();
        traditionalSofa.printInfo();
    }
}

这个示例中,我们创建了两个类来分别表示现代风格和传统风格的家具制造商。每个家具制造商都有自己的 createChair()createSofa() 方法来创建相应类型的家具对象。

在客户端代码中,我们创建了具体的家具制造商对象(即 ModernFurnitureMakerTraditionalFurnitureMaker),并使用它们来创建家具对象。然后我们打印了每个家具对象的信息。

虽然这个示例没有使用抽象工厂模式,但是它依然可以满足基本的需求。但是当需要制作的家里越多时,就会出现越来越多重复的代码。

不使用抽象工厂模式的不好之处可能包括:

  1. 不易于扩展:如果要添加新的产品类型,就需要修改所有创建产品的代码。这种修改可能会涉及多个类,不容易维护。
  2. 与具体产品实现绑定:客户端直接依赖具体的产品实现,而不是一个接口或抽象类。这使得客户端代码和具体产品实现紧密绑定在一起,难以进行替换或测试。(耦合度高)
  3. 可能导致代码重复:如果多个客户端需要创建相同类型的产品,就需要在每个客户端中复制相同的创建代码。这种代码重复可能会增加维护成本,并且容易出现错误。

2.2 使用抽象工厂模式实现

抽象产品类:

/**
 * 抽象产品类-椅子
 */
public interface Chair {
    void printInfo();
}
/**
 * 抽象产品类-沙发
 */
public interface Sofa {
  void printInfo();
}

具体产品类:

/**
 * @author Shier
 * 具体产品类-现代椅子
 */
public class ModernChair implements Chair {
    public void printInfo() {
        System.out.println("类型: 椅子, 风格: 现代, 价格: 150.0");
    }
}
/**
 * @author Shier
 * 具体产品类-现代沙发
 */
public class ModernSofa implements Sofa {
  public void printInfo() {
    System.out.println("类型: 沙发, 风格: 现代, 价格: 500.0");
  }
}
/**
 * @author Shier
 * 具体产品类-传统椅子
 */
public class TraditionalChair implements Chair {
    public void printInfo() {
        System.out.println("类型: 椅子, 风格: 传统, 价格: 100.0");

    }
}
/**
 * @author Shier
 * 具体产品类-传统沙发
 */
public class TraditionalSofa implements Sofa {
  public void printInfo() {
    System.out.println("类型: 沙发, 风格: 传统, 价格: 600.0");
  }
}

具体产品工厂类:

/**
 * @author Shier
 * 具体工厂类-现代风格家具
 */
public class ModernFurnitureFactory implements FurnitureMaker {
    public Chair createChair() {
        return new ModernChair();
    }

    public Sofa createSofa() {
        return new ModernSofa();
    }
}
/**
 * @author Shier
 * 具体工厂类-传统风格家具
 */
public class TraditionalFurnitureFactory implements FurnitureMaker {
  public Chair createChair() {
    return new TraditionalChair();
  }

  public Sofa createSofa() {
    return new TraditionalSofa();
  }
}

客户端类:

/**
 * @author Shier
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 创建现代风格家具工厂
        FurnitureMaker modernFactory = new ModernFurnitureFactory();
        Chair modernChair = modernFactory.createChair();
        Sofa modernSofa = modernFactory.createSofa();
        // 打印信息
        modernChair.printInfo();
        modernSofa.printInfo();
        // 创建传统风格家具工厂
        FurnitureMaker traditionalFactory = new TraditionalFurnitureFactory();
        Chair traditionalChair = traditionalFactory.createChair();
        Sofa traditionalSofa = traditionalFactory.createSofa();
        // 打印信息
        traditionalChair.printInfo();
        traditionalSofa.printInfo();
    }
}

我们首先创建了 ChairSofa 两个抽象产品类,代表不同类型的家具。然后,我们创建了每个具体产品类来实现相应的产品。

接下来,我们创建了 FurnitureMaker 抽象工厂类,其中包含了 createChair()createSofa() 两个抽象方法。每个具体工厂类都需要实现这些方法来创建相应类型的家具对象。

在客户端代码中,我们创建了具体的家具制造商对象(即 ModernFurnitureFactoryTraditionalFurnitureFactory),并使用它们来创建家具对象。然后我们打印了每个家具对象的信息。

虽然看上去比不使用抽象工厂方法创建了更多的类,但是通过使用抽象工厂模式,我们可以将产品的创建与具体产品实现分离,并且可以方便地添加新的产品类型或修改现有的产品实现,而无需修改客户端代码

3、抽象工厂模式总结

抽象工厂模式的优点:

  1. 可以确保客户端使用的是同一类产品对象,从而避免了不同的产品之间的兼容性问题。
  2. 在一个应用中只需要在初始化的时候出 现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
  3. 隐藏了具体产品的实现,从而使客户端代码与具体产品实现分离,增强了可扩展性和灵活性。让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
  4. 系统更易于扩展,因为增加新的具体工厂和产品族很容易,无需修改原有代码。

抽象工厂模式的缺点:

  1. 当需要添加新的产品族时,需要修改抽象工厂的接口,这将导致所有具体工厂都需要进行修改,系统变得不稳定。
  2. 当需要添加新的产品对象时,除了添加新的具体产品类外,还需要修改抽象工厂接口和所有具体工厂类,这将导致系统的维护成本增加。
  3. 在增加抽象层的同时,也增加了系统的复杂度和理解难度。

抽象工厂模式适用于以下情况:

  1. 系统需要一组相关或相互依赖的对象,而这些对象通常具有共同的接口。
  2. 系统不关心具体产品如何创建、实现等细节,只关心产品的规格和功能。
  3. 系统中有多个产品族,每个产品族都有一些共同的约束条件,这些约束条件不是通过类的继承关系来实现的。

常见的应用场景包括:

  1. 用户界面工具包:例如需要创建不同风格(如 Windows、Mac OS、Linux 等)下的按钮、文本框等界面组件,可以使用抽象工厂模式来为每个风格创建一个工厂,工厂可以创建所需的所有组件。
  2. 数据访问库:例如需要为 Oracle、MySQL、SQL Server 等不同数据库提供数据访问对象,可以使用抽象工厂模式为每个数据库创建一个工厂,工厂可以创建所需的连接、命令等对象。(在《大话设计模式》就是拿这个例子来说明抽象工厂模式的)
  3. 医疗设备控制系统:例如需要控制不同型号的医疗器械(如心电图仪、血压计、药品泵等),每个型号的设备都有自己的控制协议,可以使用抽象工厂模式为每个设备型号创建一个工厂,工厂可以创建控制该型号设备的对象。

系统不关心具体产品如何创建、实现等细节,只关心产品的规格和功能。
3. 系统中有多个产品族,每个产品族都有一些共同的约束条件,这些约束条件不是通过类的继承关系来实现的。

常见的应用场景包括:

  1. 用户界面工具包:例如需要创建不同风格(如 Windows、Mac OS、Linux 等)下的按钮、文本框等界面组件,可以使用抽象工厂模式来为每个风格创建一个工厂,工厂可以创建所需的所有组件。
  2. 数据访问库:例如需要为 Oracle、MySQL、SQL Server 等不同数据库提供数据访问对象,可以使用抽象工厂模式为每个数据库创建一个工厂,工厂可以创建所需的连接、命令等对象。(在《大话设计模式》就是拿这个例子来说明抽象工厂模式的)
  3. 医疗设备控制系统:例如需要控制不同型号的医疗器械(如心电图仪、血压计、药品泵等),每个型号的设备都有自己的控制协议,可以使用抽象工厂模式为每个设备型号创建一个工厂,工厂可以创建控制该型号设备的对象。

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

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

相关文章

MATLAB按照曲线模型拟合数据

用到了曲线拟合工具箱,如果没有下载需要另外安装: 没有下载的话在命令行内输入cftool不会弹出窗口,而是提示没有这个命令 在菜单栏的APP: 点击获取更多APP: 在弹出的窗口输入Curve Fitting Toolbox 注意这里输入cft…

100种思维模型之多维视角思维模型-70

“多维视角思维模型”让我们用众生之眼看世界,继而看见更真实世界的思维模型。 01、何谓多维度视角思维模型 一、多维度视角 所谓多维视角,指的是除了用自己本能的视角看待问题,还会用360度其他人的视角,如对立面的视角&#xff…

仅用自然语言,让ChatGPT输出连贯的长篇小说!苏黎世联邦理工大学提出RecurrentGPT

夕小瑶科技说 原创 作者 | ZenMoore,Wangchunshu Zhou 前言 ChatGPT 是万能的吗? 显然不是,至少在今天我们所讨论的长文本生成上,ChatGPT 可以说是几乎完全不太可能生成长篇小说。 在某种程度上,这是 Transformer 模…

2自由度并联关节的制作

1. 运动功能说明 2自由度并联关节模组的主要运动方式为用舵机带动连杆摆动。 2. 结构说明 构成本模组的零部件主要是舵机(行程0度~180度)、舵机支架、舵机输出头、连杆、螺丝、螺母等。此模组的机械系统介绍及运动学算法讲解可参考【R306】5自由度并联机…

回收站不见了怎么恢复?3个方法快速解决!

案例:我想把需要删除的软件拖到桌面回收站中进行删除,却发现我电脑桌面上的回收站不见了,有小伙伴知道怎么恢复吗? 在日常使用电脑的过程中,回收站是一个至关重要的功能。当我们删除文件时,它提供了一个安…

git 远端分支管理、仓库迁移:017

1. 在Github上创建分支: 2. 在Github上删除分支: 3. 使用命令来删除远端分支: 如果远端分支发生改变, 需要通过git pull来获取远端最新分支,如下图,就可以看到获取到了最新分支: 查看本地分支和…

springboot+vue新闻稿件java在线投稿管理系统

本文介绍了新闻稿件管理系统的开发全过程。通过分析新闻稿件管理系统管理的不足,创建了一个计算机管理新闻稿件管理系统的方案。文章介绍了新闻稿件管理系统的系统分析部分,包括可行性分析等,系统设计部分主要介绍了系统功能设计和数据库设计…

数据库整理

文章目录 1、将Excel转换为CSV1.1 代码 2、将CSV文件的数据追加到另一个CSV文件2.1 代码 3 、另外的发现 背景:在数据库里面导出来一批excel文件,现在需要将这些数据进行合并为csv文件 分两步: 1、将Excel转换为CSV 参考:用Pytho…

如何使用宝塔面板搭建网站(搭建宝塔页面)

书接上回,咱们已经搭建好咱们的Linux服务器,接下来改是搭建宝塔页面的教程了。 这里我们需要一个域名,自行去各家云服务器购买域名(例如:腾讯云,阿里云,华为云等等) 购买一个域名之…

FPGA纯vhdl实现XGMII接口10G万兆网UDP协议DMA传输 配合10G Ethernet PCS/PMA使用 提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、详细设计方案传统UDP网络通信方案本方案详细设计说明DMA和BRAMAXIS-FIFO10G-UDP协议栈10G Ethernet PCS/PMA IP核输出 4、vivado工程详解Block Design设计SDK设计 5、上板调试验证并演示6、福利:工程代码的获取 1、前言 目前…

【ChatGPT】开发人员教程:38 种提高 10 倍工作效率的方法(附Youtube视频地址)...

1. 推荐3本顶级的学习xx的书籍 2. 询问细节:“Head first Java”的主要内容是什么?What are the key takeaways from "Head first Java"? 3. 我如何成为一名前端开发人员?How do I become a front-end developer? (英…

JVM-常用工具(jps、jstat、jinfo、jmap、jhat、jstack、jconsole、jvisualvm)使用

场景 记录JVM中常用工具。 jps:虚拟机进程状态工具 jps(JVM Process Status Tool):虚拟机进程状态工具,可以列出正在运行的虚拟机进程, 并显示虚拟机执行主类(Main Class,main()函数所在的类)的名称&am…

【Mininet】安装篇:安装Mininet

大家好,我是皮皮猫吖! 每文一言:改变你的生活,现在或者从不 本篇文章: 本文是安装 mininet 的简单过程。 正文如下: 一、Mininet的安装 第一步:安装git apt install git 第二步&#xff…

element-ui配置按需引入和全局引入

镇楼图 按需引入 安装element-plus cnpm install element-plus --save 安装按需导入 cnpm install -D unplugin-vue-components unplugin-auto-import修改vite.config.js配置按需加载 import AutoImport from unplugin-auto-import/viteimport Components from unplugin-vue-…

30天从入门到精通TensorFlow1.x第一天,如何创建张量

文章目录 一、TensorFlow基本概念1. 什么是TensorFlow2. TensorFlow的组成3. TensorFlow的三个重要模型 二、TensorFlow的重要底层库1. 先简单来个 helloWord2. 张量什么是张量如何创建张量创建张量(1). 通过定义常量来进行创建张量(2&#x…

Java学习笔记21——常用API

常用API 常用APIMath类Math的常用方法 System类System类常用方法 Object类Object类常用方法 Arrays类Arrays常用方法 基本类型包装类Integer类的概述和使用int和String的相互转换自动装箱和拆箱 日期类Date类Date类的常用方法 SimpleDateFormat类SimpleDateFormat的构造方法Sim…

【计算机网络实验】静态路由协议和RIP协议仿真实验

实验内容  静态路由协议和RIP协议仿真实验 实验目的 1 路由器及路由协议基础知识 2 静态路由配置实验 (1)掌握静态路由和RIP的配置方法; (2)掌握通过静态路由和RIP方式实现网络的连通性; (3…

什么是品牌推广?品牌推广的基本概念及注意要点

品牌推广是企业进行营销活动的关键之一,而现代市场竞争激烈,如何进行有效的品牌推广也成为企业最为关心的问题之一。本文将为大家介绍品牌推广的基本概念、策略以及注意事项。 一、品牌推广的基本概念 品牌推广是指企业通过多种手段,以宣传产…

电脑软件:键盘按键修改器——keytweak使用介绍

对你的电脑键盘的布局不满意、键盘上的某个按键坏掉了等等键盘问题如何解决?有了KeyTweak这一切就可以轻松解决了,KeyTweak是一个免费软件程序,使用它可让你重新映射键盘键。如果您改变主意并想将其改回原样,只需点击一下即可容易…

如何拍摄家具

产品可视化在几乎所有企业中都至关重要,尤其是电子商务,93%的消费者认为视觉外观是购买决策的关键因素。对于家具公司也是一样的。这是您在市场上建立知名度、吸引潜在客户并让他们购买的方式之一。更不用说如今,客户的要求比以往任何时候都高…