当前位置: 首页 > news >正文

设计模式——工厂模式(简单工厂、工厂方法、抽象工厂)

是什么?

工厂模式的目的是将创建对象的具体过程隐藏起来,从而达到更高的灵活性

工厂模式分为:简单工厂模式、工厂方法模式、抽象工厂模式

为什么?

在Java中,万物皆是对象,我们在使用的时候这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,那么所有new的地方都需要修改一遍,这明显违背了设计原则中的开闭原则,如果我们使用工厂来生产对象,那么我们只需要和工厂打交道就好了,彻底和对象解耦,如果要更换对象,直接在工厂中更换该对象即可,达到了与该对象解耦的目的,因此工厂模式最大的优点就是:解耦

简单工厂模式

简单工厂不是一个设计模式,它更像是一种编码习惯

结构

抽象产品:定义了产品的规模,描述了产品的主要特性和功能。

具体产品:实现或者继承抽象产品的子类。

具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品。

实现

产品类:

public class Car {  //汽车父类private String getName;}
public class Tesla extends Car{   //子类-特斯拉汽车public Tesla() {System.out.println("()=>制造特斯拉汽车");}
}
public class Benz extends Car{  //子类-奔驰汽车public Benz() {System.out.println("()=>制造奔驰汽车");}
}

工厂类及用户使用:

public class SimpleFactory {/*** 。模拟简单工厂模式* */public Car getCar(String type){    //汽车“生产间”=》简单工厂if ("Benz".equals(type)){return new Benz();}if ("Tesla".equals(type)){return new Tesla();}return new Car();}
}
public class Customer {//消费者直接调用的是工厂而非对象本身,这样就将用户和创建对象的过程隔离开来了public static void main(String[] args) {SimpleFactory simpleFactory = new SimpleFactory();simpleFactory.getCar("Benz");}
}

优缺点

我们会发现,在简单工厂模式中,提供了专门的工厂类来帮助我们创建对象,实现了对象创建和用户使用的职责分离,客户端不需要知道所创建的产品类名以及创建过程只需要知道具体产品类所需要的参数即可,通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性;

但是这样做也是不符合“开闭原则的”,如果我们这个时候需要再添加一个BMW汽车,那么同样的需要去修改我们的工厂类,在产品类型较多的时候,有可能造成工厂逻辑过于复杂,不利于系统的横向扩展和维护,并且工厂类集中了所有产品的创建逻辑,如果不能正常工作那么整个系统都会受到影响

为了解决简单工厂出现的问题,引入了我们的工厂方法模式

工厂方法模式

定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象,工厂方法使一个产品类的实例化延迟到其工厂的子类;

结构

抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品;

具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建;

抽象产品:定义了产品的规范,描述了产品的主要特性和功能;

具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应;

实现

产品类:

public class Car {// 产品父类}public class Benz extends Car{  //子类产品public Benz() {System.out.println("()=>制造奔驰汽车");}
}
public class Tesla extends Car{   //子类产品2public Tesla() {System.out.println("()=>制造特斯拉汽车");}
}

抽象工厂

public interface AbstractFactoryInterface {  //抽象工厂Car createCar();
}

具体工厂及用户使用

public class BenzFactory implements AbstractFactoryInterface{  //具体子类工厂@Overridepublic Car createCar() {return new Benz();}
}public class TeslaFactory implements AbstractFactoryInterface{  //具体子类工厂2@Overridepublic Car createCar() {return new Tesla();}
}
public class Customer {   //用户类public static void main(String[] args) {Car car = new BenzFactory().createCar();Car car2 = new TeslaFactory().createCar();}
}

那么我们这个时候还需要添加一个BMW车的话,只需要创建一个BMW类去继承Car,并且再去创建一个BMW的工厂去实现抽象工厂即可,不需要去修改原来的代码,问题即得到解决;

优缺点

用户只需要知道具体工厂的名称即可得到所要的产品,也不需要知道产品具体的类和创建过程,在系统增加新的产品的时候只需要添加具体产品类和对应具体工厂类,无需对源代码进行任何修改,满足开闭原则;

但是每增加一个产品就需要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度;

抽象工厂模式

我们前面介绍的工厂方法模式中考虑的是一类产品的生产,如车厂只生产车,畜牧场只生产动物;

这些工厂只生产同种类的产品,也就是说工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂都是综合型的工厂,能够生产多等级的产品,例如一个畜牧场它不仅生产动物,还生产饲料粮食,汽车厂不仅生产汽车,还生产发动机、汽车配饰等等;

因此抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族如下:横轴是产品等级,也就是同一类产品,纵轴是产品族,也就是同一品牌的产品(产自同一个工厂);

也就是说它是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构;

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可以生产多个等级的产品;

结构

抽象工厂:提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品;

具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建;

抽象产品:定义了产品的规模,描述的产品的主要特性和功能,抽象工厂模式中有多个抽象产品;

具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它与具体工厂之间是多对一的关系;

实现

也就是说我们现在车厂不仅要生产车,还要生产车的配饰、配件等等;

抽象产品及具体产品

public class Engine {public Engine() {}
}public class V12Engine extends Engine{public V12Engine() {System.out.println("这是V12发动机");}
}public class V8Engine extends Engine{public V8Engine() {System.out.println("这是V8发动机");}
}public class Acc {public Acc() {}
}
public class Cowhide extends Acc{public Cowhide() {System.out.println("这是牛皮坐垫");}
}public class Common extends Acc{public Common() {System.out.println("这是普通坐垫");}
}

抽象工厂

public interface AbstractFactory {//抽象工厂,定义创建具体工厂的规范Acc createAcc();Engine createEngine();
}

具体工厂

public class TeslaFactory implements AbstractFactory{//不同的具体产品根据自己的生产需求去创建不同的对象@Overridepublic Acc createAcc() {return new Cowhide();}@Overridepublic Engine createEngine() {return new V12Engine();}
}public class BMWFactory implements AbstractFactory{@Overridepublic Acc createAcc() {return new Common();}@Overridepublic Engine createEngine() {return new V8Engine();}
}

用户

public class Customer {public static void main(String[] args) {TeslaFactory teslaFactory = new TeslaFactory();teslaFactory.createEngine();teslaFactory.createAcc();System.out.println("————————————————————————");BMWFactory bmwFactory = new BMWFactory();bmwFactory.createAcc();bmwFactory.createEngine();}
}

 优缺点

当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象;

但是当产品组中需要增加一个新的产品时所有的工厂类都需要进行修改;

例如我如果想要再添加一个空调这个产品,不仅需要多一个空调的产品族,并且在抽象工厂中还需要添加一个创建空调的方法;

相关文章:

设计模式——工厂模式(简单工厂、工厂方法、抽象工厂)

是什么? 工厂模式的目的是将创建对象的具体过程隐藏起来,从而达到更高的灵活性 工厂模式分为:简单工厂模式、工厂方法模式、抽象工厂模式; 为什么? 在Java中,万物皆是对象,我们在使用的时候…...

《C语言技术体系》 学习路线总目录 + 思维导图

目录 前言 正文 思维导图 第1章 流程结构 1.1 初识C语言 1.2 流程结构 1.3 数据类型 1.4 运算符表达式 第2章 指针与数组 2.1 指针基本概念 2.2 一维数组 2.3 二维及多维数组 2.4 指针与数组 第3章 模块化重构 3.1 函数 3.2 typedef类型定义 3.3 enum枚举 3.…...

数字图像处理简答题

目录 1.人类视觉对颜色的主观感觉包括哪三类? 2. 图像成像的过程包括哪三步? 3.图像的采样和量化分别指什么? 4、取k8时,将下图用相应矩阵表示 5、简述当限定了数字图像的数据量时采样和量化参数的选择遵循哪两条原则&#x…...

【Java校招面试】基础知识(五)——GC

目录 前言一、基础概念二、垃圾回收算法三、垃圾收集器四、引用后记 前言 本篇主要介绍Java垃圾回收机制——GC的相关内容。 “基础知识”是本专栏的第一个部分,本篇博文是第五篇博文,如有需要,可: 点击这里,返回本专…...

使用CMake调用Makefile 项目

目录标题 基本示例Cmake传递lib给MakefileCmake传递参数给Makefile,比如make cleanWindows下使用Cmake调用Makefile 基本示例 如果项目是使用传统的Makefile构建的,并且您希望使用CMake调用这些Makefile,您可以使用CMake的add_custom_target…...

快速傅里叶变换FFT学习笔记

点值表示法 我们正常表示一个多项式的方式,形如 A ( x ) a 0 a 1 x a 2 x 2 . . . a n x n A(x)a_0a_1xa_2x^2...a_nx^n A(x)a0​a1​xa2​x2...an​xn,这是正常人容易看懂的,但是,我们还有一种表示法。 我们知道&#xf…...

如何下载安装驱动

1 打开浏览器 这里以Edge浏览器举例 第一步打开桌面上的Edge浏览器 如果您的桌面上没有 那么找到搜索栏 搜索Edge 然后打开 打开之后一般是这样 然后把我发送您的地址 驱动下载地址 https://t.lenovo.com.cn/yfeyfYyD (这个网址只是一个例子) 删除掉前…...

鸿蒙Hi3861学习四-Huawei LiteOS介绍

一、什么是LitesOS Huawei LiteOS是华为针对物联网领域推出的轻量级物联网操作系统,是华为物联网战略的重要组成部分,具备轻量级、低功耗、互联互通、组件丰富、快速开发等关键能力。基于物联网领域业务特征打造领域性技术栈,为开发者提供“一…...

Vue核心 收集表单数据 过滤器

1.14. 收集表单数据 收集表单数据: 若: ,则v-model收集的是value值,用户输入的就是value值。若: ,则v-model收集的是value值,且要给标签配置value值。若: 没有配置input的value属性,那么收集的就是checked(勾选 or 未…...

华为EC6108V9E/EC6108V9I_rk3228_安卓4.4.4_通刷_卡刷固件包

华为EC6108V9E/EC6108V9I_rk3228_安卓4.4.4_通刷_卡刷固件包-内有教程 特点: 1、适用于对应型号的电视盒子刷机; 2、开放原厂固件屏蔽的市场安装和u盘安装apk; 3、修改dns,三网通用; 4、大量精简内置的…...

数字化转型导师坚鹏:面向数字化转型的大数据顶层设计实践

面向数字化转型的大数据顶层设计实践 课程背景: 数字化背景下,很多企业存在以下问题: 不清楚大数据思维如何建立? 不清楚企业大数据分析方法? 不了解大数据应用成功案例? 课程特色: …...

day27_mysql

今日内容 零、 复习昨日 一、单表查询 二、多表联查 零、 复习昨日 1 DDL,DML,DQL是啥 DDL 数据定义语言(库,表,列)DML 数据操作语言(表内数据的操作增删改)DQL 数据查询语言(表内数据的查询&am…...

QwtPlotCurve使用说明

QwtPlotCurve是Qwt库中用于绘制曲线的类,可以在QwtPlot上绘制各种类型的曲线,如折线、样条线、散点等。以下是QwtPlotCurve的一些常用函数和使用说明: setSamples(const QPolygonF &samples):设置曲线的数据点,参数…...

JS逆向 -- 某平台登录加密分析

一、打开网站,使用账号密码登录 账号:aiyou123.com 密码:123456 二、通过F12抓包,抓到如下数据,发现密码加密了 三、加密结果是32位,首先考虑是md5加密。 四、全局搜索pwd,点击右上角&#xf…...

一分钟快速实现Flask框架的蓝图和视图

一分钟快速实现Flask框架的蓝图和视图 Flask是一个轻量级的Web应用框架,非常适合快速开发小型的Web应用。Flask框架使用蓝图(Blueprint)和视图(View)的概念来组织应用程序的代码。在本文中,我们将介绍如何…...

Mysql 约束练习【第13章_约束】

#第13章_约束 /* 基础知识 1.1 为什么需要约束? 为了保证数据的完整性! 1.2 什么叫约束?对表中字段的限制。 1.3 约束的分类: 角度1:约束的字段的个数 单列约束 vs 多列约束 角度2:约束的作用范围 列…...

java调用cmd命令

1.首先,我们需要了解一下 java是如何调用 cmd的: 6.在实际的开发中,我们有可能会遇到 java调用 cmd命令的情况: 7.对于一些特定的环境下,例如在嵌入式系统中,那么我们可以使用下面这种方式来调用 cmd命令&a…...

Qt音视频开发36-超时检测和自动重连的设计

一、前言 如果网络环境正常设备正常,视频监控系统一般都是按照正常运行下去,不会出现什么问题,但是实际情况会很不同,奇奇怪怪七七八八的问题都会出现,就比如网络出了问题都有很多情况(交换机故障、网线故障、带宽故障等),所以监控系统在运行过程中,还得做超时检测,…...

Reactor 第九篇 WebFlux重构个人中心,效果显著

1 重构背景 原有的开发人员早已离职,代码细节没人知道,经过了一段时间的维护,发现有以下问题: 个人中心系统的特征就是组装各个业务的接口,输出个人中心业务需要的数据,整个系统调用了几十个第三方业务线的…...

Vben Admin 自学记录 —— Drawer组件的基本使用及练习(持续更新中...)

Drawer 抽屉组件 对 antv 的 drawer 组件进行封装,扩展拖拽,全屏,自适应高度等功能。 Drawer相关使用及概念 练习 —— 在之前table基础上,添加查看功能,点击查看按钮,弹出抽屉显示单条表格数据&#xf…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

条件运算符

C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...