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

重学设计模式-工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)

在平常的学习和工作中,我们创建对象一般会直接用new,但是很多时候直接new会存在一些问题,而且直接new会让我们的代码变得非常繁杂,这时候就会巧妙的用到设计模式,平常我们通过力扣学习的算法可能并不会在我们工作中用到,但设计模式基本上我们所参加的每一个项目都会有。

今天来学习讲解一下工厂模式,这个也是我认为最常见的设计模式之一

1.什么是工厂模式

工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,工厂模式可以分为三类:
简单工厂模式(Simple Factory)
工厂方法模式(Factory Method)
抽象工厂模式(Abstract Factory)
这三种模式从上到下逐步抽象,并且更具一般性。《设计模式》一书中将工厂模式分为两类:工厂方法模式与抽象工厂模式。将简单工厂模式看为工厂方法模式的一种特例,两者归为一类。 我们先从学校食堂窗口案例对工厂模式做个初步的了解:

  1. 没有工厂模式:在没有工厂模式的情况下,我们食堂窗口就类似于米饭,馒头,面条这些都需要我们自己创建,我们需要告诉窗口具体需要什么产品,然后自己创建
  2. 简单工厂模式:在简单工厂模式下,我们就不需要自己创建了,而是让食堂阿姨创建,但是简单工厂模式下只有一个工厂,也就是只有一个窗口,我们需要在这一个窗口选取我们所需要的食物
  3. 工厂方法模式:在工厂方法模式下,每一个食物就对应一个窗口,比如说分为米饭窗口,馒头窗口,面条窗口,我们需要什么仅需要去对应窗口买就可以了
  4. 抽象工厂模式:在抽象工厂模式下,每一个事物可能有多种组成成分,每一个窗口,可以生成多个食品以及食品组成成分,比如说有一个清真窗口,我们需要刀削面加牛肉,或者刀削面加羊肉,就仅需在这一个清真窗口把我们所需的参数传进去,就会我们生成对应的对象。

2.简单工厂模式

简单工厂模式的逻辑就是将定义一个创建对象的接口,将接口的创建和业务逻辑分开,我们需要修改逻辑仅需要去修改工厂里面的内容即可,降低耦合性。

在这里插入图片描述
上面就是简单工厂的uml图,简单工厂由于比较好理解一般来说仅有一个角色就是产品工厂,我们将需要的参数提交给简单工厂,简单工厂就会将产品生产出来。

代码实现:
产品类

abstract class food {public food(){}
}public class noodles extends food {public noodles () {System.out.println("制造-->noodles ");}
}
public class rice extends BMW{public rice (){System.out.println("制造-->rice ");}
}

工厂类:

public class Factory {public food createfood(int type) {switch (type) {case 1:return new rice();case 2:return new noodles();default:break;}return null;}
}

用户类:

public class Users{Factory factory = new Factory();food rice = factory.createfood(1);food noodles = factory.createfood(2);
}

上述之所以用1,2仅仅是为了方便写代码。

简单工厂模式的优缺点都很明显,有点就是解耦,缺点就是我们每次增加或者修改产品都需要去修改工厂类,如果项目规模特别大的话,这显然是无法接受的。

3 工厂方法模式

工厂方法模式将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。在使用时,用于只需知道产品对应的具体工厂,关注具体的创建过程,甚至不需要知道具体产品类的类名,当我们选择哪个具体工厂时,就已经决定了实际创建的产品是哪个了。

来自小付哥在这里插入图片描述
工厂方法一半分为四个角色
抽象工厂:每个具体工厂需要继承抽象工厂,一般来说用抽象类来实现
具体工厂:需要继承抽象工厂,生产具体产品,一般是具体生产逻辑
抽象产品:具体产品需要继承,有时候也可以没有
具体产品:我们所具体需要的对象

代码示例

产品类:

abstract class food{public food(){}
}
public class noodles extends food{public noodles () {System.out.println("制造-->noodles ");}
}
public class rice extends food{public rice (){System.out.println("制造-->rice ");}
}

工厂类:

interface Factoryfood {BMW createfood();
}public class Factorynoodles implements Factoryfood{@Overridepublic noodles createfood() {return new BMWnoodles();}}
public class Factoryrice implements Factoryfood {@Overridepublic rice createfood() {return new rice();}
}

用户类:

public class Customer {public static void main(String[] args) {Factoryrice factoryrice = new Factoryrice();rice = factoryrice.createrice();Factorynoodles factorynoodles = new Factorynoodles();noodles noodles = factorynoodles.createnoodles();}
}

4.抽象工厂模式

工厂方法模式中,一个工厂生成具体产品,但是正如我文章开头所说,我们所需要的可能不仅仅是一个产品,而是一个产品加某些组件,或者说有几个产品我们需要在一个工厂内生产。此时工厂方法模式就不再适用。

抽象工厂模式提供一个工厂生产多个组件+产品的功能,简单的说一个工厂生产的是一个产品族
在这里插入图片描述

抽象工厂 AbstractFactory:定义了一个接口,这个接口包含了一组方法用来生产产品,所有的具体工厂都必须实现此接口。
具体工厂 ConcreteFactory:用于生产不同产品族,要创建一个产品,用户只需使用其中一个工厂进行获取,完全不需要实例化任何产品对象。
抽象产品 AbstractProduct:这是一个产品家族,每一个具体工厂都能够生产一整组产品。
具体产品 Product

抽象工厂相对来说没那么好理解,建议大家阅读一下下面的代码
代码示例:
产品类:


public interface Engine {}  public class EngineA implements Engine{  public EngineA(){  System.out.println("制造-->EngineA");  }  
}  
public class EngineB implements Engine{  public EngineB(){  System.out.println("制造-->EngineB");  }  
}  public interface Aircondition {} public class AirconditionA implements Aircondition{  public AirconditionA(){  System.out.println("制造-->AirconditionA");  }  
}  
public class AirconditionB implements Aircondition{  public AirconditionB(){  System.out.println("制造-->AirconditionB");  }  
} 

工厂类

//创建工厂的接口  
public interface AbstractFactory {  public Engine createEngine();public Aircondition createAircondition(); 
}  public class Factoryrice implements AbstractFactory{     @Override  public Engine createEngine() {    return new EngineA();  }  @Override  public Aircondition createAircondition() {  return new AirconditionA();  }  
}  
//宝马523系列
public class Factorynoodles implements AbstractFactory {  @Override  public Engine createEngine() {    return new EngineB();  }  @Override  public Aircondition createAircondition() {  return new AirconditionB();  }  
} 

用户类:

public class Customer {  public static void main(String[] args){  FactoryBMW320 factoryrice = new Factoryrice();  factoryBMW320.createEngine();factoryBMW320.createAircondition();FactoryBMW523 factorynoodles = new Factorynoodles();  factoryBMW523.createEngine();factoryBMW523.createAircondition();}  
}

5.工厂模式小结

工厂模式主要是通过工厂这个对象来解耦,面对不同需求采用不同的工厂模式,切忌硬套代码模板

工厂模式应该是我们平常用到的最多的设计模式之一,但大家不要盲目去用,有很多用ifelse能够很简单解决的业务也可以不用工厂模式,不然到时候反而增加了我们的代码复杂度。

后面还会持续更新各种设计模式

相关文章:

重学设计模式-工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)

在平常的学习和工作中,我们创建对象一般会直接用new,但是很多时候直接new会存在一些问题,而且直接new会让我们的代码变得非常繁杂,这时候就会巧妙的用到设计模式,平常我们通过力扣学习的算法可能并不会在我们工作中用到…...

【C语言】结构体(四)

本篇重点是typedef关键字 一,是什么? typedef用来定义新的数据类型,通常typedef与结构体的定义配合使用。 简单来说就是取别名 ▶ struct 是用来定义新的数据类型——结构体 ▶ typedef是给数据类型取别名。 二,为什么&#xf…...

swift类方法为什么使用表派发?

直接上答案:因为表派发允许子类重写父类的方法,并在运行时根据对象的实际类型调用正确的方法实现。 什么是表派发? 首先我们先知道的是,swift当中函数的派发机制主要分为静态派发和动态派发。动态派发又分为表派发和消息派发。 …...

php实现AES/CBC/PKCS5Padding加密

接口文档 文档给过来的案例是java程序的,参照其思路,造一个php版本 构造aes对称加密 public static function encry($data){$data "要加密的数据";$key 你的256位密钥; // 密钥应该是16字节(128位),24字节…...

Anaconda3安装及使用

Anaconda3安装及使用 Linux中安装Anaconda31.安装 Anaconda32.配置环境变量3.验证是否成功 Conda环境和包管理1.Conda 环境初始化2.Conda Env 管理3.Conda 软件包管理 Linux中安装Anaconda3 下面是在Linux中安装Anaconda3-2021.05的教程,其他版本Anaconda更换名字即…...

Argon2-cffi与argon2-cffi-bindings:深入理解及其应用

Argon2-cffi与argon2-cffi-bindings的关系 在Python密码学领域,argon2-cffi和argon2-cffi-bindings是两个经常被提及的库。尽管它们的名字相似,但它们在实现和用途上有所不同。argon2-cffi是一个提供Argon2哈希算法的Python库,而argon2-cffi-…...

spring boot+jpa接入达梦数据库

文章目录 前言依赖配置对应的domain类和repository 前言 最近有一个新项目,由于信息安全等要求只能使用达梦数据库(dm8),之前从来没用过,特此开一个笔记记录一下spring bootjpa如何使用达梦数据库完成开发。 依赖 p…...

Vite构建,用NodeJS搭建一个简单的Vite服务

Vite 是一个现代的前端构建工具,由 Vue.js 作者尤雨溪创建。它主要用于开发和构建现代 JavaScript 应用,尤其是单页应用(SPA)。Vite 相比于传统的构建工具(如 Webpack)有几个显著的优势: 即时开…...

R语言机器学习论文(六):总结

文章目录 介绍参考文献介绍 本文采用R语言对来自进行数据描述、数据预处理、特征筛选和模型构建。 最后我们获得了一个能有效区分乳腺组织的随机森林预测模型,它的性能非常好,这意味着它可能拥有非常好的临床价值。 在本文中,我们利用R语言对来自美国加州大学欧文分校的B…...

python---面向对象---综合案例(4)

案例描述 实现加减乘法运算 # _*_ encoding:utf-8 _*_# 计算器, 实现一些基本的操作, 加减乘除运算, 以及打印结果操作# ------------------------------------代码1-------------------------------------- def jia(n1, n2):return n1 n2def jian(n1, n2):return n1 - n2de…...

如何参加华为欧拉考试?

华为欧拉考试主要针对的是华为欧拉(EulerOS/openEuler)操作系统的认证考试,这一认证体系旨在培养和认证具备基于欧拉操作系统进行企业级应用运行基础环境搭建、管理和调测能力的工程师以及云计算架构师。以下是对华为欧拉考试的详细介绍&…...

算法预刷题Day9:BM28 二叉树的最大深度

描述: 描述 求给定二叉树的最大深度, 深度是指树的根节点到任一叶子节点路径上节点的数量。 最大深度是所有叶子节点的深度的最大值。 (注:叶子节点是指没有子节点的节点。) 思路: 当前节点的最大高度 ma…...

exp_lr_scheduler理解

1. exp_lr_scheduler理解 这行代码定义了一个学习率调度器,用于动态调整训练过程中优化器的学习率。让我们分解并解释其含义: 1. exp_lr_scheduler 是什么? exp_lr_scheduler 是一个 学习率调度器(LR Scheduler),由 torch.optim.lr_scheduler.StepLR 创建,旨在按照预…...

Algorithm:河内之塔

1. 说明 河内之塔(Towers of Hanoi)是法国人 M.Claus(Lucas)于1883年从泰国带至法国的,河内为越战时北越的首都,即现在的胡志明市;1883年法国数学家 Edouard Lucas 曾提及这个故事,据…...

集中管理与实时审计:构建Linux集群(1300台服务器)日志平台的最佳实践

简介 随着企业IT基础设施的不断扩大,Linux服务器的数量也日益增多,传统的单机日志管理方式已无法满足对日志数据集中管理、审计和分析的需求。尤其是在大型集群环境中,如何高效地收集、存储和分析日志成为了一项重要的技术挑战。 背景 在实…...

在Scala中Array不可变的学习

package gjhs114import scala.collection.mutable.ArrayBuffer object Arrray114 {// 不可变数组:Array// def main(args: Array[String]): Unit {1 创建不可变数组// val arr1 Array(1,2,3)//2 访问.数组名(下标)。下标是从0开始到…...

vue3+vite 批量引入组件动态使用

import { ref, reactive, toRaw, markRaw, defineAsyncComponent, onMounted } from vue import type { Component } from vue// vue3vite 批量引入组件动态使用 const modules import.meta.glob<Component>(./details/*.vue) // 明确指定导入的模块类型为Component con…...

设计模式——方法链or流式接口

方法链或流式接口是一种编程模式或设计模式。核心思想是通过返回对象自身的应用&#xff0c;使得可以在一个表达式中连续调用多个方法。 c中实现这种模式 1.基本语法规则 &#xff08;1&#xff09;每个可链接的方法都返回对象自身的引用&#xff08;通常是*this&#xff09…...

JAVA OPCUA 服务端开发,客户端连接会话监听和订阅事件监听

前言 关于使用milo开源库,开发opc ua服务器,有网友咨询如何设置服务端如何监听客户端的连接或断开事件,如何监听客户端发起订阅事件的代码实现,于是我完善了这部分的空缺整理整了这篇教程,希望能解决有同样需求,但是遇到困难的网友!因为milo没有官方文档的教程且网上详…...

pytest相关总结

1.pytest -v -s -v将测试用例名称和用例中的输出进行展示&#xff0c;将每条用例脚本的内容逐行进行结果展示&#xff1b; -s 参数是为了显示用例执行层级的打印信息 pytest使用总结笔记 - fengf233 - 博客园 2....

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

Qt Quick Controls模块功能及架构

Qt Quick Controls是Qt Quick的一个附加模块&#xff0c;提供了一套用于构建完整用户界面的UI控件。在Qt 6.0中&#xff0c;这个模块经历了重大重构和改进。 一、主要功能和特点 1. 架构重构 完全重写了底层架构&#xff0c;与Qt Quick更紧密集成 移除了对Qt Widgets的依赖&…...

AT模式下的全局锁冲突如何解决?

一、全局锁冲突解决方案 1. 业务层重试机制&#xff08;推荐方案&#xff09; Service public class OrderService {GlobalTransactionalRetryable(maxAttempts 3, backoff Backoff(delay 100))public void createOrder(OrderDTO order) {// 库存扣减&#xff08;自动加全…...

break 语句和 continue 语句

break语句和continue语句都具有跳转作用&#xff0c;可以让代码不按既有的顺序执行 break break语句用于跳出代码块或循环 1 2 3 4 5 6 for (var i 0; i < 5; i) { if (i 3){ break; } console.log(i); } continue continue语句用于立即终…...

盲盒一番赏小程序:引领盲盒新潮流

在盲盒市场日益火爆的今天&#xff0c;如何才能在众多盲盒产品中脱颖而出&#xff1f;盲盒一番赏小程序给出了答案&#xff0c;它以创新的玩法和优质的服务&#xff0c;引领着盲盒新潮流。 一番赏小程序的最大特色在于其独特的赏品分级制度。赏品分为多个等级&#xff0c;从普…...