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

3、设计模式之工厂模式1

工厂模式是什么?
    工厂模式是一种创建者模式,用于封装和管理对象的创建,屏蔽了大量的创建细节,根据抽象程度不同,主要分为简单工厂模式、工厂方法模式以及抽象工厂模式。

简单工厂模式
看一个具体的需求
看一个披萨的项目:要便于披萨种类的扩展,要便于维护

  1. 披萨的种类很多(比如 GreekPizz、CheesePizz 等)
  2. 披萨的制作有 prepare,bake, cut, box
  3. 完成披萨店订购功能

使用传统的方式来完成

步骤一:创建一个Pizza抽象类

public abstract class Pizza {
protected String name;
public abstract void prepare();
public void bake() {
System.out.println(name + " baking;");
}
public void cut() {
System.out.println(name + " cutting;");
}
public void box() {
System.out.println(name + " boxing;");
}
public void setName(String name) {
this.name = name;
}}

步骤二:创建两个披萨类

public class CheesePizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("奶酪pizza");
System.out.println(name + " preparing;");
}}
public class GreekPizza extends Pizza {
@Override
public void prepare() {
setName("GreekPizza");
System.out.println(name + " preparing;");
}}

步骤三:制定订购披萨类

public class OrderPizza {public OrderPizza() {Pizza pizza = null;do {String pizzaType = getType();if ("cheese".equalsIgnoreCase(pizzaType)) {pizza = new CheesePizza();pizza.setName("cheese");} else if ("beef".equalsIgnoreCase(pizzaType)) {pizza = new BeefPizza();pizza.setName("beef");} else {break;}pizza.prepare();pizza.bake();pizza.cut();pizza.box();} while (true);}// 写一个方法,可以获取希望订购的披萨种类private String getType() {try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 种类:");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}
}

分析: 慢慢看代码,可以明白,订购披萨的逻辑代码写在了该类的构造器中,getType()方法是用来获取希望订购的披萨种类。但是,如果我们需要添加新的披萨,就需要从这个类中继续添加相应的逻辑语句,从而修改了订购披萨的这个类,就违反了OCP原则

步骤四:创建运行类

 public class PizzaStore {public static void main(String[] args) {new OrderPizza();}
}

运行结果:
在这里插入图片描述
优缺点分析
优点:比较好理解,简单易操作
缺点:违反了设计模式的ocp原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码

使用简单工厂

基本介绍
简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
简单工厂模式定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式

步骤一:创建简单工厂


public class SimpleFactory {public static Pizza createPizza2(String orderType) {Pizza pizza = null;if ("beef".equalsIgnoreCase(orderType)) {pizza = new BeefPizza();pizza.setName(" beef ");} else if ("cheese".equalsIgnoreCase(orderType)) {pizza = new CheesePizza();pizza.setName("cheese");}return pizza;}
}

分析: 简单工厂又叫做静态工厂,我们写一个静态方法,可以方便后面代码的调用,这里用到的类,跟用传统方法用到的类一样,没有改变

步骤二:制定订购披萨类

public class OrderPizza2 {public OrderPizza2() {do {String orderType = getType();Pizza pizza = SimpleFactory.createPizza2(orderType);if (pizza != null) {pizza.prepare();pizza.bake();pizza.cut();pizza.box();} else {System.out.println(" 订购披萨失败 ");break;}} while (true);}private String getType() {try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 种类:");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}
}

分析: 该类的构造器中用到了简单工厂类SimpleFactory,这样,我们就不需要在订购披萨这一行为中去写增加新的披萨的代码了,而是从工厂中写添加新的披萨的代码,就不用再改动这个类。

运行结果:
在这里插入图片描述
优点分析
使用简单工厂模式来创建对象,更加的方便灵活,不需要修改订购披萨的逻辑

使用工厂方法
新的需求
客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪pizza、北京的胡椒pizza 或者是伦敦的奶酪pizza、伦敦的胡椒pizza

基本介绍
工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
步骤概括
步骤一:创建四个披萨类

public class BJCheesePizza extends Pizza {@Overridepublic void prepare() {setName("北京的奶酪pizza");System.out.println("北京的奶酪pizza 准备原材料");}
}

分析: Pizza类跟上面的代码一样,我就没有再次写了。此类是用来创建北京的奶酪口味的披萨

public class BJPepperPizza extends Pizza{@Overridepublic void prepare() {setName("北京的胡椒pizza");System.out.println("北京的胡椒pizza 准备原材料");}
}

分析: 此类是用来创建北京的辣椒口味的披萨

public class LDCheesePizza extends Pizza {@Overridepublic void prepare() {setName("伦敦的奶酪pizza");System.out.println("伦敦的奶酪pizza 准备原材料");}
}

分析: 此类是用来创建伦敦的奶酪口味的披萨

public class LDPepperPizza extends Pizza {@Overridepublic void prepare() {setName("伦敦的胡椒pizza");System.out.println("伦敦的胡椒pizza 准备原材料");}
}

分析: 此类是用来创建伦敦的辣椒口味的披萨

步骤二:创建订购披萨抽象类

public abstract class OrderPizza {abstract Pizza createPizza(String orderType);public OrderPizza() {do {String orderType = getType();Pizza pizza = createPizza(orderType); //抽象方法,由工厂子类完成if (pizza == null){System.out.println("订购披萨失败");break;}pizza.prepare();pizza.bake();pizza.cut();pizza.box();} while (true);}private String getType() {try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 种类:");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}
}

分析: 此类中定义一个抽象方法createPizza(), 让各个工厂子类自己实现,构造器中写订购披萨的代码逻辑;getType()方法跟原来的没有区别。

public class BJOrderPizza extends OrderPizza {@OverridePizza createPizza(String orderType) {Pizza pizza = null;if(orderType.equals("cheese")) {pizza = new BJCheesePizza();} else if (orderType.equals("pepper")) {pizza = new BJPepperPizza();}return pizza;}
}

分析: 此类用来继承OrderPizza类,成为北京地区的订购披萨分销商

public class LDOrderPizza extends OrderPizza {@OverridePizza createPizza(String orderType) {Pizza pizza = null;if(orderType.equals("cheese")) {pizza = new LDCheesePizza();} else if (orderType.equals("pepper")) {pizza = new LDPepperPizza();}return pizza;}
}

分析: 此类也用来继承OrderPizza类,成为伦敦地区的订购披萨分销商

步骤三:创建运行类

public class PizzaStore {public static void main(String[] args) {String loc = "beijing";if (loc.equals("beijing")) {new BJOrderPizza();} else {new LDOrderPizza();}}
}

分析: 假设就是买北京地区的披萨

运行结果:
在这里插入图片描述
使用抽象工厂
基本介绍
抽象工厂模式定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类
抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合
从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)
将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
步骤一:创建总工厂接口

public interface AbsFactory {public Pizza createPizza(String orderType);
}

分析: 此类是用来让下面的工厂子类来具体实现

步骤二:创建分工厂

public class BJFactory implements AbsFactory {@Overridepublic Pizza createPizza(String orderType) {Pizza pizza = null;if(orderType.equals("cheese")) {pizza = new BJCheesePizza();} else if (orderType.equals("pepper")){pizza = new BJPepperPizza();}return pizza;}
}

分析: 这是工厂子类,用来制作北京的披萨

public class LDFactory implements AbsFactory {@Overridepublic Pizza createPizza(String orderType) {Pizza pizza = null;if (orderType.equals("cheese")) {pizza = new LDCheesePizza();} else if (orderType.equals("pepper")) {pizza = new LDPepperPizza();}return pizza;}
}

分析: 这是工厂子类,用来制作伦敦的披萨

步骤三:创建订购类

public class OrderPizza {private AbsFactory factory;public OrderPizza(AbsFactory factory) {setFactory(factory);}private void setFactory(AbsFactory factory) {do {this.factory = factory;String orderType = getType();// factory 可能是北京的工厂子类,也可能是伦敦的工厂子类Pizza pizza = factory.createPizza(orderType);if (pizza == null) { System.out.println("订购失败");break;}pizza.prepare();pizza.bake();pizza.cut();pizza.box();} while (true);}   private String getType() {try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 种类:");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}
}

步骤四:创建运行类

public class PizzaStore {public static void main(String[] args) {new OrderPizza(new LDFactory());}
}

分析: 假设买的是伦敦地区的披萨

运行结果:
在这里插入图片描述

总结
1、工厂模式的意义:

将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
2、三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式)

3、设计模式的依赖抽象原则

创建对象实例时,不要直接 new 类, 而是把这个new 类的动作放在一个工厂的方法中,并返回
不要让类继承具体类,而是继承抽象类或者是实现interface(接口)
不要覆盖基类中已经实现的方法。

相关文章:

3、设计模式之工厂模式1

工厂模式是什么?     工厂模式是一种创建者模式,用于封装和管理对象的创建,屏蔽了大量的创建细节,根据抽象程度不同,主要分为简单工厂模式、工厂方法模式以及抽象工厂模式。 简单工厂模式 看一个具体的需求 看一个…...

一个Promise全新API

1. 资讯速览 最近,Promise 新出了一个方法,已经进入 Stage 3 (候选阶段) ,相信很快就能达到 Stage 4 (完成阶段),并在项目中广泛使用。 这个方法就是 Promise.withResolvers。它是…...

【力扣hot100】刷题笔记Day25

前言 这几天搞工作处理数据真是类似我也,还被老板打电话push压力有点大的,还好搞的差不多了,明天再汇报,赶紧偷闲再刷几道题(可恶,被打破连更记录了)这几天刷的是动态规划,由于很成…...

webpack5零基础入门-4使用webpack处理less文件

1.安装less npm install less -D 2.创建less文件 .box{width: 100px;height: 100px;background: red; } 3.引入less文件并打包 执行npx webpack 报错无法识别less文件 4.安装less-loader并配置 npm install less-loader9 -D 这里指定一下版本不然会因为node版本过低报错 …...

Python机器学习预测+回归全家桶,新增TCN,BiTCN,TCN-GRU,BiTCN-BiGRU等组合模型预测...

截止到本期,一共发了4篇关于机器学习预测全家桶Python代码的文章。参考往期文章如下: 1.机器学习预测全家桶-Python,一次性搞定多/单特征输入,多/单步预测!最强模板! 2.机器学习预测全家桶-Python&#xff…...

一文了解Cornerstone3D中窗宽窗位的3种设置场景及原理

🔆 引言 在使用Cornerstone3D渲染影像时,有一个常用功能“设置窗宽窗位(windowWidth&windowLevel)”,通过精确调整窗宽窗位,医生能够更清晰地区分各种组织,如区别软组织、骨骼、脑组织等。…...

部署 LVS(nginx)+keepalived高可用负载均衡集群

目录 一、集群的概述 1、什么是集群 2、普通集群与负载均衡集群 2.1 普通集群(Regular Cluster) 2.2 负载均衡集群(Load Balancing Cluster) 2.3 高可用集群(High Availability Cluster) 2.4 区别 …...

Qt/QML编程之路:fork、vfork、exec、clone的对比及使用(46)

前言: 系统调用system call是OS提供的服务提供接口。系统调用fork()、vfork()、exec()和clone()都用于创建和操作进程。Linux下Qt编程也会用到vfork进行多进程间通信。让我们看一下以下每个系统调用的概述和比较: fork()、vfork()和clone()的工作原理相似,但在处…...

Go语言框架路由Controller控制器设计思路gin路由根据控制器目录分层生成路由地址

Controller设计好处 框架设计用controller分请求路由层级,应用从app目录开始对应请求url路由地址,这样设计师方便开发时候通过请求地址层级快速定位接口方法对应的代码位置。 例如api接口请求路径为:​​http://localhost:8110/​​busines…...

突破编程_C++_设计模式(责任链模式)

1 责任链模式的概念 责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许对象以链式的方式组织起来,以便对请求进行处理。这种模式为多个对象处理同一请求提供了一个灵活的机制,而无需在发送者和多…...

php开发100问?

什么是 PHP?PHP 是一种什么类型的语言?PHP 的优缺点是什么?如何在服务器上配置 PHP?PHP 中的变量是如何声明和使用的?如何在 PHP 中输出文本和变量?什么是 PHP 的数据类型?如何在 PHP 中实现条件…...

flink实战--Flink任务资源自动化优化

背景 在生产环境Flink任务资源是用户在实时平台端进行配置,用户本身对于实时任务具体配置多少资源经验较少,所以存在用户资源配置较多,但实际使用不到的情形。比如一个 Flink 任务实际上 4 个并发能够满足业务处理需求,结果用户配置了 16 个并发,这种情况会导致实时计算资…...

tsv文件在大数据技术栈里的应用场景

是的,\t 是指制表符(tab),它通常用作字段分隔符在 TSV(Tab-Separated Values)格式的文件中。TSV是一种简单的文本格式,它使用制表符来分隔每一列中的值,而每一行则代表一个数据记录。…...

vscode设置setting.json

{ // vscode默认启用了根据文件类型自动设置tabsize的选项 "editor.detectIndentation": false, // 重新设定tabsize "editor.tabSize": 2, // #每次保存的时候自动格式化 // "editor.formatOnSave": true, // #每次保存的时候将代码按eslint格式…...

Docker的安装及镜像加速的配置

文章目录 一.切换到root二.卸载旧版docker三.配置docker的yum库四.安装Docker五.Docker的启动和验证六.配置Docker阿里云镜像加速(全程免费) 该文章文章演示在Linux系统中安装docker,Windows安装docker请参考以下文章 Windows系统中安装docker及镜像加速的配置 一…...

AIGC时代IT人的迷茫有解(1):从“商业画布”到“个人画布”

IT人的迷茫和心态调整 最近打开新闻,各种IT老大都在说“AIGC时代,只要会说话,人人都会具备程序员的能力”,身边也有很多程序员朋友也已经在用GPT类的产品编程了。随着AIGC的发展,除了程序员,可能很多职业都会被替代或…...

Qt/QML编程之路:openglwidget和倒车影像的切换(43)

关于如何实现一个基于OpenGL的3d 图形,这个有很多专门的介绍,我在开发中遇到了这么一个问题: 如何实现一个倒车影像的video显示与一个3D物体显示的切换,因为开窗在同样的一个位置,如果车子倒车启动,则需要将原本显示3D的地方切换为视频图像的显示。 class testOpenGl : …...

Spring 初学者遇到的问题

TagLibraryValidator Spring 实战 5.2 中有个表单需要在 jsp 中遍历数组&#xff0c;添加&#xff1a;<% taglib uri"http://java.sun.com/jsp/jstl/core" prefix"c" %>&#xff0c;访问时发现有些问题&#xff1a; java.lang.NoClassDefFoundError…...

前端解决跨域问题( 6种方法 )

本专栏是汇集了一些HTML常常被遗忘的知识&#xff0c;这里算是温故而知新&#xff0c;往往这些零碎的知识点&#xff0c;在你开发中能起到炸惊效果。我们每个人都没有过目不忘&#xff0c;过久不忘的本事&#xff0c;就让这一点点知识慢慢渗透你的脑海。 本专栏的风格是力求简洁…...

Linux 理解进程

目录 一、基本概念 二、描述进程-PCB 1、task_struct-PCB的一种 2、task_ struct内容分类 三、组织进程 四、查看进程 1、ps指令 2、top命令 3、/proc文件系统 4、在/proc文件中查看指定进程 5、进程的工作目录 五、通过系统调用获取进程标示符 1、getpid()/get…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...