设计模式之抽象工厂

文章目录

  • 一、介绍
  • 二、基本组件
  • 三、演示案例
    • 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() 中,我们可以再次结合单例模式来避免频繁实例化婚庆公司对象。

四、总结

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


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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测(含KELM、ELM等对比)

时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测(含KELM、ELM等对比) 目录 时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测(含KELM、ELM等对比)预测效果基本介绍模型介绍程序设计参…

【javaweb】学习日记Day3 - Ajax 前后端分离开发 入门

目录 一、Ajax 1、简介 2、Axios (没懂 暂留) (1)请求方式别名 (2)发送get请求 (3)发送post请求 (4)案例 二、前端工程化 1、Vue项目-目录结构 2、…

java 里面 long 转换int内存分析

了解补码知识点 要将补码转换为十进制,需要确定补码的符号位。如果补码的符号位为1,则表示为负数,否则表示为正数。 假设我们有一个补码为1 0110 1011 1100 1101 1000 0011 1101 1100 0010 1101 1111 1101 1100 0001 1100 0011 0100 首先&a…

在其他python环境中使用jupyter notebook

1、切换到目标python环境 activate 目标python环境 2、安装notebook内核包 pip install ipykernel 3、加环境加入到notebook中 python -m ipykernel install 目标python环境 4、切换到base环境 activate base 5、打开目标项目的对应盘 如果,项目在c盘&…

web基础http与apache

一、http相关概念: http概述: HTTP 是一种用作获取诸如 HTML 文档这类资源的协议。它是 Web 上进行任何数据交换的基础,同时,也是一种客户端—服务器(client-server)协议 为解决"用什么样的网络协…

二叉树链式结构的实现

文章目录 1.前置说明 2.二叉树的遍历 文章内容 1.前置说明 学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在我们对于二叉树的了解还处于初级阶段,所以我们手动创建一棵简单的二叉树,以便…

SPI2外设驱动-W25Q64 SPI接口初始化

前言 (1)本系列是基于STM32的项目笔记,内容涵盖了STM32各种外设的使用,由浅入深。 (2)小编使用的单片机是STM32F105RCT6,项目笔记基于小编的实际项目,但是博客中的内容适用于各种单片…

React 使用 useRef() 获取循环中所有子组件实例

目录 背景思考实现完整代码:成功运行后的界面如下: 知识点总结uesRef() 作对象处理useImperativeHandle() 父组件操作引入子组件的内部方法最后 背景 之前项目中使用了antd pro 中的 可编辑表格 (EditableProTable),在页面中表格要经过多层遍…

远程连接虚拟机中ubuntu报错:Network error:Connection refused

ping检测一下虚拟机 可以ping通,说明主机是没问题 #检查ssh是否安装: ps -e |grep ssh发现ssh没有安装 #安装openssh-server sudo apt-get install openssh-server#启动ssh service ssh startps -e |grep ssh检查一下防火墙 #防火墙状态查看 sudo ufw…

云原生之使用Docker部署SSCMS内容管理系统

云原生之使用Docker部署SSCMS内容管理系统 一、SSCMS介绍二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载SSCMS镜像五、部署SSCMS内容管理系统5.1 创建SSCMS容器5.2 检查SSC…

2023.8 -java - 继承

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。 继承的特性 子类拥有父类非 private 的属性、方法。 子类可以拥有自己的属性和方法…

深度学习11:Transformer

目录 什么是 Transformer? Encoder Decoder Attention Self-Attention Context-Attention 什么是 Transformer(微软研究院笨笨) RNN和Transformer区别 Universal Transformer和Transformer 区别 什么是 Transformer? ​ …

【校招VIP】TCP/IP模型之常用协议和端口

考点介绍: 大厂测试校招面试里经常会出现TCP/IP模型的考察,TCP/IP协议是网络基础知识,是互联网的基石,不管你是做开发、运维还是信息安全的,TCP/IP 协议都是你绕不过去的一环,程序员需要像学会看书写字一样…

Typora上使用Mermaid语法展示流程图、时序图、甘特图

你已经安装Typora并打开了一个新文档后,可以按照以下详细步骤在Typora上使用Mermaid语法展示流程图、时序图、甘特图 流程图 使用graph LR声明开始,并使用箭头和连接符号定义节点之间的关系。例如,A --> B表示从节点A指向节点B的箭头连接。graph TB A[界面布局图] -->…

EasyPOI 实战总结

EasyPOI实战总结 简介 easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板 语言(熟悉的表达式语法),完成以前复杂的写法 使用EasyPOI 环境搭建 # 1.引入相关依…

TensorFlow中slim包的具体用法

TensorFlow中slim包的具体用法 1、训练脚本文件(该文件包含数据下载打包、模型训练,模型评估流程)3、模型训练1、数据集相关模块:2、设置网络模型模块3、数据预处理模块4、定义损失loss5、定义优化器模块 本次使用的TensorFlow版本…

Leetcode 2235.两整数相加

一、两整数相加 给你两个整数 num1 和 num2,返回这两个整数的和。 示例 1: 输入:num1 12, num2 5 输出:17 解释:num1 是 12,num2 是 5 ,它们的和是 12 5 17 ,因此返回 17 。示例…

【OCR识别】tess4j图片识别文字

什么是OCR? OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机…

ServiceManager接收APP的跨进程Binder通信流程分析

现在一起来分析Server端接收(来自APP端)Binder数据的整个过程,还是以ServiceManager这个Server为例进行分析,这是一个至下而上的分析过程。 在分析之前先思考ServiceManager是什么?它其实是一个独立的进程,由init解析i…

【人脸考勤项目】

本项目主要是基于Opencv完成的人脸识别的考勤系统 人脸检测器的5种实现方法 方法一:haar方法进行实现(以下是基于notebook进行编码) # 步骤 # 1、读取包含人脸的图片 # 2.使用haar模型识别人脸 # 3.将识别结果用矩形框画出来# 导入相关包 …