设计模式之抽象工厂

news2024/11/20 2:30:18

文章目录

  • 一、介绍
  • 二、基本组件
  • 三、演示案例
    • 1. 定义抽象工厂
    • 2. 定义抽象产品
    • 3. 定义具体工厂
    • 4. 定义具体产品
    • 5. 代码演示
    • 6. 代码改造
  • 四、总结

一、介绍

抽象工厂模式(Abstract Factory Pattern)属于创建型设计模式。用于解决比工厂方法设计模式更加复杂的问题。

复杂到哪里了呢?

我们将抽象工厂模式和工厂模式进行简单的比较,或许可以有更好的理解:

  • 工厂方法设计模式中,指定工厂只能创建对应的单个产品,是一对一的关系。
  • 抽象工厂模式中,不仅需要创建产品的工厂,还多了一个创建工厂的工厂(顶级工厂)。当顶级工厂创建一个工厂时,顶级工厂与工厂是一对一的关系(等同于工厂模式),被创建的工厂可以生产多个产品,因此顶级工厂与产品之间是一对多的关系。

二、基本组件

在我们使用抽象工厂设计模式时,一般需要以下组件:

  • 抽象工厂
  • 工厂实现
  • 抽象产品
  • 产品实现

一般来讲,从抽象工厂中获取的对象类型为抽象类型,其具体类型由具体的工厂实现决定。

三、演示案例

唉,到了结婚的年纪了,我们就以结婚为例吧。

1. 定义抽象工厂

结婚是一件十分麻烦的事情,需要准备非常非常多的事情,比如婚车婚房婚纱照等等。所以我们以结婚为工厂,以婚车婚房婚纱照为产品。先对结婚这件事情做一个规范的定义。

  public interface MarriageFactory {
      /**
       * 产品 - 婚车
       */
      Car getCar();
      /**
       * 产品 - 婚房
       */
      House getHouse();
      /**
       * 产品 - 婚纱照
       */
      Picture getPicture();
  }

2. 定义抽象产品

  • 婚车

    public interface Car {
    
        /**
         * 坐婚车
         */
        void drive();
    }
    
  • 婚房

    public interface House {
        /**
         * 买房
         */
        void buyHouse();
    }
    
  • 婚纱照

    public interface Picture {
    
        /**
         * 照相
         */
        void takePicture();
    }
    

3. 定义具体工厂

我们结婚一般都是要找一个婚庆公司,假设婚庆公司都提供结婚的一条龙服务,包括婚车、婚房、婚纱照等业务,现在我们城里有两家婚庆公司:汤姆婚庆(TomFactory)杰瑞婚庆(JerryFactory)

  • 汤姆婚庆(TomFactory)

    汤姆婚庆公司提供具有汤姆特色的业务,如汤姆婚车(TomCar)汤姆婚房(TomHouse)汤姆照相(TomPicture)

    public class TomFactory implements MarriageFactory {
        public TomFactory() {
            System.out.println("选择了汤姆婚庆公司");
        }
        
        @Override
        public Car getCar() {
            return new TomCar();
        }
    
        @Override
        public House getHouse() {
            return new TomHouse();
        }
    
        @Override
        public Picture getPicture() {
            return new TomPicture();
        }
    }
    
  • 杰瑞婚庆(JerryFactory)

    杰瑞婚庆公司提供具有杰瑞特色的业务,如杰瑞婚车(TomCar)杰瑞婚房(TomHouse)杰瑞照相(TomPicture)

    public class JerryFactory implements MarriageFactory {
        public JerryFactory() {
            System.out.println("选择了杰瑞婚庆公司");
        }
        
        @Override
        public Car getCar() {
            return new JerryCar();
        }
    
        @Override
        public House getHouse() {
            return new JerryHouse();
        }
    
        @Override
        public Picture getPicture() {
            return new JerryPicture();
        }
    }
    

4. 定义具体产品

  • 汤姆婚庆公司提供具有汤姆特色的业务,如汤姆婚车(TomCar)汤姆婚房(TomHouse)汤姆照相(TomPicture)

    public class TomCar implements Car{
        /**
         * 婚车
         */
        @Override
        public void drive() {
            System.out.println("汤姆婚车开起来...");
        }
    }
    
    public class TomHouse implements House{
    
        /**
         * 买房
         */
        @Override
        public void buyHouse() {
            System.out.println("汤姆一品房价50w.....");
        }
    }
    
    public class TomPicture implements Picture{
    
        /**
         * 照相
         */
        @Override
        public void takePicture() {
            System.out.println("汤姆照相馆照相.....");
        }
    }
    
  • 杰瑞婚庆公司提供的业务具有杰瑞特色,如杰瑞婚车(TomCar)杰瑞婚房(TomHouse)杰瑞照相(TomPicture)

    public class JerryCar implements Car{
        /**
         * 婚车
         */
        @Override
        public void drive() {
            System.out.println("杰瑞婚车开起来...");
        }
    }
    
    public class JerryHouse implements House{
    
        /**
         * 买房
         */
        @Override
        public void buyHouse() {
            System.out.println("杰瑞一品房价30w...");
        }
    }
    
    public class JerryPicture implements Picture{
    
        /**
         * 照相
         */
        @Override
        public void takePicture() {
            System.out.println("杰瑞照相馆照相.....");
        }
    }
    

5. 代码演示

下面我们对上述案例进行代码演示

  • 选择杰瑞婚庆公司

    public static void main(String[] args) {
    
        // 选择杰瑞婚庆公司
        MarriageFactory factory = new JerryFactory();
        Car car = factory.getCar();
        House house = factory.getHouse();
        Picture picture = factory.getPicture();
    
        car.drive();
        house.buyHouse();
        picture.takePicture();
    }
    

    输出结果:

    在这里插入图片描述

  • 选择汤姆婚庆公司

    public static void main(String[] args) {
    
        // 选择杰瑞婚庆公司
        MarriageFactory factory = new TomFactory();
        Car car = factory.getCar();
        House house = factory.getHouse();
        Picture picture = factory.getPicture();
    
        car.drive();
        house.buyHouse();
        picture.takePicture();
    }
    

    输出结果:

    在这里插入图片描述

6. 代码改造

在上面的测试代码中我们注意到,我们只是对new 婚庆公司的实际类型做了修改,而产品相关代码没有任何改动。于是我们可以将对婚庆公司的实例化过程按照工厂方法设计模式那样转移到工厂中,只需要抽象工厂根据传入的参数返回不同的工厂实例即可。

  • 在抽象工厂中添加静态方法getInstance() 和 枚举类MarriageType

    static MarriageFactory getInstance(MarriageType type) {
        if (type.equals(MarriageType.JERRY)) {
            return new JerryFactory();
        }
        return new TomFactory();
    }
    
    enum MarriageType {
        JERRY,
        TOM;
    }
    
  • 修改测试代码

    public static void main(String[] args) {
    
        // 选择杰瑞婚庆公司
        MarriageFactory factory = MarriageFactory.getInstance(MarriageFactory.MarriageType.JERRY);
        Car car = factory.getCar();
        House house = factory.getHouse();
        Picture picture = factory.getPicture();
    
        car.drive();
        house.buyHouse();
        picture.takePicture();
    }
    

另外,在静态方法getInstance() 中,我们可以再次结合单例模式来避免频繁实例化婚庆公司对象。

四、总结

  • 抽象工厂与工厂方法的最主要区别就是:抽象工厂允许创建多个产品;而工厂方法只允许创建一个产品
  • 该设计模式有一个致命缺点:每当我们在工厂中添加新的产品时,工厂的抽象和具体实现都需要修改。当工厂的具体实现较多时,每一个实现都必须适配新添加的产品。


纸上得来终觉浅,绝知此事要躬行。

————————我是万万岁,我们下期再见————————

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

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

相关文章

U盘怎么加密?U盘加密方法有哪些?

U盘是我们生活和工作中最常用的移动储存设备,经常被用来存放各种重要数据,为了保证数据的安全,我们需要加密U盘。那么,U盘加密方法有哪些呢? U盘加密普通方法 如果你的U盘储存数据不多,并且对于加密的要求…

Orchestrator介绍三 命令行工具

Orchestrator-client orchestrator 支持两种方式通过命令行操作: 一种是 通过命令 orchestrator: 需要在服务器上安装 orchestrator,但是可以不作为服务启动。 需要配置orchestrator的文件,以便能够连接后端数据库 一种是通过…

Docker部署gogs仓库

Docker部署gogs Git仓库 拉取镜像 docker pull gogs/gogs查看本地镜像 docker images启动gogs仓库服务 创建数据挂在目录 我在/root目录下创建gogs挂在目录 mkdir gogs启动gogs docker run --namegogs -d -p 10022:22 -p 10880:3000 -v /root/gogs:/data gogs/gogs10022…

知识图谱Neo4j安装到实践全过程

前言: Hello大家好,我是Dream。 在本次实战中,我们将一起完成知识图谱Neo4j安装到实践全过程,探索其中的关系和属性。知识图谱是一种以三元组形式存储的数据结构,由实体、关系和属性组成,能够帮助我们更好地…

西部AI小镇-构建自主虚拟世界

背景 未来曜文有接入市场上所有面向chatGPT开发的应用,例如开源聊天组件,西部小镇等 内容介绍 生成代理起床,做早餐,然后去上班;艺术家作画,作家写作;他们形成意见、互相关注并发起对话&…

window如何实时刷新日志文件

1 安装windows git 下载地址:Git - Downloading Package (git-scm.com) 2 打开git bash 输入tail.exe -f 日志文件路径

yo!这里是Linux权限入门理解

目录 前言 权限概念 权限管理 分类 1.用户 2.文件&&目录 表示 设置 1.chmod指令 2.chown指令 3.chgrp指令 4.umask指令 粘滞位 后记 前言 对于Linux基本指令,基本上就是操作文件或者目录,但是,是谁可以操作文件或目录&…

8个月打磨,打造出的全能工具箱,让你事半功倍!

这款工具叫即时工具,目前有网页端和客户端可以下载至本地离线使用,区别在于客户端采用原生适配性能更好,网页端需要上传至服务器或浏览器内部处理。 体验地址:点击直达 一、为什么会开发这个工具 综合性和多功能性:…

MySQL数据库 索引、事务、储存引擎

索引 索引的概念 索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址(类似于C语言的链表通过指针指向数据记录的内存地址)。 使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找…

harbor升级后镜像项目访问无权限问题

一、问题背景 将环境中现运行的harbor版本升级到2.6.2版本,相关同事升级完,发现有部分镜像项目点进去报无权限问题,镜像项目无法使用,但是也有部分项目是可以正常提供使用的。 二、问题处理过程 1、根据报错反馈没权限&#xff…

【Flutter】Flutter 使用 device_info_plus 获取设备的制造商、型号等信息

【Flutter】Flutter 使用 device_info_plus 获取设备的制造商、型号等信息 文章目录 一、前言二、安装和基本使用三、实际业务中的用法四、完整示例五、总结 一、前言 在这篇博客中,我将为你介绍一个非常实用的 Flutter 插件:device_info_plus。这个插件…

基于SSM+vue框架的校园代购服务订单管理系统源码和论文

基于SSMvue框架的校园代购服务订单管理系统源码和论文070 开发工具:idea 数据库mysql5.7 数据库链接工具:navcat,小海豚等 技术:ssm 摘 要 在新发展的时代,众多的软件被开发出来,给用户带来了很大的选择余地&am…

调查问卷平台哪家好?

在如今的数字化时代,问卷调查已成为企业和组织了解顾客需求、员工满意度以及市场趋势的重要工具。然而,在众多的在线调查工具中,为什么我们要选择Zoho Survey? 一、强大的功能和灵活的问卷设计 1、多种问卷题型: Zo…

浪潮信息 KeyarchOS 助力 IT 企业安全管理业务完成 CentOS 迁移替换 | 龙蜥案例

前言 安全稳定是操作系统永恒的追求,某知名 IT 企业的安全管理业务服务于公司多个业务,涵盖代码安全管理平台、数字签名平台以及内部使用的多个研发平台,其底层运行着 CentOS 7 操作系统。随着 CentOS 各操作系统版本陆续停服,将…

掌握指针和数组:经典笔试题攻略(万字详解)

🍁博客主页:江池俊的博客 💫收录专栏:C语言刷题专栏 💡代码仓库:江池俊的代码仓库 🎪我的社区:GeekHub 🎉欢迎大家点赞👍评论📝收藏⭐ 文章目录 前…

最新docker多系统安装技术

在Ubuntu操作系统中安装Docker 在Ubuntu操作系统中安装Docker的步骤如下。 1.卸载旧版本Docker 卸载旧版本Docker的命令如下: $ sudo apt-get remove docker docker-engine docker.io 2.使用脚本自动安装 在测试或开发环境中&#xff0…

聊聊敏捷实践的“个体与交互”

这是鼎叔的第七十二篇原创文章。行业大牛和刚毕业的小白,都可以进来聊聊。 欢迎关注本公众号《敏捷测试转型》,星标收藏,大量原创思考文章陆续推出。 敏捷宣言有重要的一句话:个体和交互胜过过程和工具。作为工程师,…

【实训项目】“享学”APP设计

1.设计摘要 随着高等教育普及化程度提高,国家对大学生的要求也越来越高,在学习过程中总会遇到各种各样的阻碍,很多学生苦于找不到资料,苦于找不到适合自己的资料,苦于找不到能让自己提高的资料。不善交际,…

基于Java+SpringBoot+Vue前后端分离校园失物招领系统设计和实现

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…

简单js逆向案例(1)

文章目录 声明模块分析完整代码python实现js扣代码实现 结尾 声明 本文章中所有内容仅供学习交流,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 模块 pip install Py…