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

设计模式(工厂模式,模板方法模式,单例模式)

单例模式:

确保一个类只有一个实例,并提供全局访问点。

单例模式举例:

  1. 配置信息类:用于存储应用程序的全局配置信息,例如数据库连接信息、日志配置等。

  2. 日志类:用于记录应用程序运行时的日志信息,确保在整个应用程序中只有一个日志实例

  3. 线程池类:在多线程环境下,使用单例模式可以确保只有一个线程池实例,提高资源利用率和性能。

单例模式饿汉式:

代码:

public class Singleton {/*防止外界随意使用构造方法new对象,我们需要将构造私有化*/private Singleton(){}/*为了赶紧new对象,我们new对象的时候变成静态的,让其随着类的加载而加载为了不让外界随便使用类名调用此静态对象,我们将其变成private*/private static Singleton singleton = new Singleton();/*为了将内部new出来的对象给外界我们可以定义 一个方法,将内部的对象返回给外界*/public static Singleton getSingleton(){return singleton;}
}

将new出来的对象设置为静态属性,这样随着类的加载而加载

单例模式懒汉式:

public class Singleton1 {/*防止外界随意使用构造方法new对象,我们需要将构造私有化*/private Singleton1() {}/*懒汉式,不着急new对象*/private static Singleton1 singleton1 = null;/*为了将内部new出来的对给外界定义一个方法,将内部new出来的对返回*/public static Singleton1 getSingleton1() {//如果singleton1不是null就没必要抢锁了,直接返回,是null再抢锁if (singleton1==null){synchronized (Singleton1.class){if (singleton1 == null) {singleton1 = new Singleton1();}}}return singleton1;}
}

懒汉式就不着急new对象了,留了一个公共的接口,你想new的时候就new即可

懒汉式的线程不安全问题:

这也是懒汉式的一个缺点:如果没有加锁的代码:

public static Singleton1 getSingleton1() {if (singleton1 == null) {singleton1 = new Singleton1();}return singleton1;}

这很容易引发线程不安全问题,我们设想有两个线程,第一个线程需要这个singleton1这个对象,进入了if判断,不过这个时候CPU将线程切换给了第二个线程,那这个时候,第二个线程也进入了if判断,然后CPU再切换会第一个线程,线程一创建了对象,但是我们知道线程二也进入了if判断,它也能创建对象,这就导致了线程不安全问题

饿汉式和懒汉式区别:

1:创建的时间不一样:饿汉式是在类加载过程中就创建了实例,而饿汉式是被调用的时候才创建实例

2:线程安全问题:饿汉式不存在什么线程安全,类加载的时候我就创建了,而且不能改,不可能又线程安全问题,反观饿汉式就有线程安全问题

在Spring中的单例模式的体现:

 在 Spring 源码中,最常见的使用单例设计模式的场景就是在创建 Bean 实例时使用单例模式。Spring 容器默认情况下会将所有的 Bean 对象作为单例对象进行管理,这样可以节省资源,提高性能。

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);@Overridepublic Object getSingleton(String beanName) {return this.singletonObjects.get(beanName);}@Overridepublic void registerSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {Object oldObject = this.singletonObjects.get(beanName);if (oldObject != null) {throw new IllegalStateException("Could not register object [" + singletonObject + "] under bean name '" + beanName +"': there is already object [" + oldObject + "] bound");}this.singletonObjects.put(beanName, singletonObject);}}// 其他方法...
}

这个是我在鱼皮公众号上看到的,我第一次看到这段话的时候,也是有一个疑问

创建 Bean 实例是饿汉式还是懒汉式?

然后我问了GPT:

Spring容器在启动时会预先实例化所有单例Bean对象,这样可以避免懒汉式中可能存在的线程安全问题,确保在需要使用Bean时能够立即获取到对象实例。这种预先实例化的方式类似于饿汉式,但并不完全等同于饿汉式的实现方式。


模板方法模式:

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。明确了一部分功能,而另一部分功能不明确。需要延伸到子类中实现

 这个我觉得就非常好理解:

我们平常都在写的接口或者抽象类都是这种思想

比如我们要去餐馆吃饭,我们每次餐馆都要点菜买单

不过我们去不同的餐馆点的菜都不一样

就可以把餐馆抽象成一个类,不同的餐馆都是实现类

上一段代码:

public abstract class Hotel {public void eat(){System.out.println("点菜");eatCai();System.out.println("买单");}public abstract void eatCai();
}public class QuanJuDe extends Hotel{@Overridepublic void eatCai() {System.out.println("薄饼");System.out.println("放鸭肉");System.out.println("酱");System.out.println("葱丝");System.out.println("黄瓜丝");System.out.println("卷着吃");}
}
public class ZhangLiang extends Hotel{@Overridepublic void eatCai() {System.out.println("调麻酱");System.out.println("放辣椒油");System.out.println("倒到大碗中吃");}
}public class Test01 {public static void main(String[] args) {QuanJuDe quanJuDe = new QuanJuDe();quanJuDe.eat();System.out.println("================");ZhangLiang zhangLiang = new ZhangLiang();zhangLiang.eat();}
}

 


工厂模式:

工厂模式是一种创建型设计模式,其主要目的是封装对象的实例化过程,将对象的创建和使用分离。通过工厂模式,可以实现更灵活、可扩展的对象创建方式,同时降低代码的耦合度。

工厂模式分为下面三种:简单工厂模式,工厂方法模式,抽象工厂模式


还没有工厂的时候:我们如果需要车,我们得自己去造车 自己去 new 对象
public class BMW320 {public BMW320(){System.out.println("制造-->BMW320");}
}public class BMW523 {public BMW523(){System.out.println("制造-->BMW523");}
}public class Customer {public static void main(String[] args) {BMW320 bmw320 = new BMW320();BMW523 bmw523 = new BMW523();}
}
简单工厂模式:简单工厂的时候,我们已经有了简单的工厂,我们不用自己去造车了

我们可以告诉工厂,我们需要这个这个车,工厂造好给我们即可

有一个工厂类,我们去调用工厂类的造车方法造车

产品类:

// 产品接口
interface Product {void doSomething();
}// 具体产品类 A
class ConcreteProductA implements Product {@Overridepublic void doSomething() {System.out.println("Product A is doing something.");}
}// 具体产品类 B
class ConcreteProductB implements Product {@Overridepublic void doSomething() {System.out.println("Product B is doing something.");}
}

工厂类: 

// 简单工厂类
class SimpleFactory {public static Product createProduct(String type) {if ("A".equals(type)) {return new ConcreteProductA();} else if ("B".equals(type)) {return new ConcreteProductB();}return null;}
}

客户端代码:

// 客户端代码
public class Main {public static void main(String[] args) {Product productA = SimpleFactory.createProduct("A");productA.doSomething();Product productB = SimpleFactory.createProduct("B");productB.doSomething();}
}
工厂方法模式:到了这个时候,随着车型的增多,一个工厂已经不能生成这么多车型了

就需要工厂分类:每个工厂生成一种型号的车

有一个工厂抽象类,生成各种型号的车的工厂去继承里面的造车方法

再有一个车的抽象类,不同的车去继承里面的方法
 

 

// 产品接口
interface Product {void doSomething();
}// 具体产品类 A
class ConcreteProductA implements Product {@Overridepublic void doSomething() {System.out.println("Product A is doing something.");}
}// 具体产品类 B
class ConcreteProductB implements Product {@Overridepublic void doSomething() {System.out.println("Product B is doing something.");}
}// 工厂接口
interface Factory {Product createProduct();
}// 具体工厂类 A,负责创建产品 A
class ConcreteFactoryA implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}// 具体工厂类 B,负责创建产品 B
class ConcreteFactoryB implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}// 客户端代码
public class Main {public static void main(String[] args) {Factory factoryA = new ConcreteFactoryA();Product productA = factoryA.createProduct();productA.doSomething();Factory factoryB = new ConcreteFactoryB();Product productB = factoryB.createProduct();productB.doSomething();}
}
抽象工厂模式:这个时候的需求就已经很复杂了,

每个车需要的零件都不同,比如车1和车2分别是两个不同的型号,车1需要空调a和发动机b,车2需要空调b和发动机b

这个时候就设计到了一个产品族,就是空调,发动机或者其它产品合在一起就是一个产品族

有点像我们日常生活中开店,比如我们开冷冻产品店,那我们不可能一个人去准备所有的冷冻产品,我肯定是去找对应的供货商,比如火锅料的供货商,鱿鱼的供货商,饮料的供货商,然后整合到我这个冷冻店再去销售

所以翻译成Java语言就是,空调是一个抽象类,发动机是一个抽象类,多个抽象类,一个工厂抽象类,不同型号的车是一个类都去继承这个工厂,你需要什么零件就去这个工厂里面配这个零件。

// 产品族接口
interface AbstractProductA {void doSomething();
}interface AbstractProductB {void doSomething();
}// 具体产品类 A1
class ConcreteProductA1 implements AbstractProductA {@Overridepublic void doSomething() {System.out.println("Product A1 is doing something.");}
}// 具体产品类 B1
class ConcreteProductB1 implements AbstractProductB {@Overridepublic void doSomething() {System.out.println("Product B1 is doing something.");}
}// 具体产品类 A2
class ConcreteProductA2 implements AbstractProductA {@Overridepublic void doSomething() {System.out.println("Product A2 is doing something.");}
}// 具体产品类 B2
class ConcreteProductB2 implements AbstractProductB {@Overridepublic void doSomething() {System.out.println("Product B2 is doing something.");}
}// 抽象工厂接口
interface AbstractFactory {AbstractProductA createProductA();AbstractProductB createProductB();
}// 具体工厂类 1
class ConcreteFactory1 implements AbstractFactory {@Overridepublic AbstractProductA createProductA() {return new ConcreteProductA1();}@Overridepublic AbstractProductB createProductB() {return new ConcreteProductB1();}
}// 具体工厂类 2
class ConcreteFactory2 implements AbstractFactory {@Overridepublic AbstractProductA createProductA() {return new ConcreteProductA2();}@Overridepublic AbstractProductB createProductB() {return new ConcreteProductB2();}
}// 客户端代码
public class Main {public static void main(String[] args) {AbstractFactory factory1 = new ConcreteFactory1();AbstractProductA productA1 = factory1.createProductA();AbstractProductB productB1 = factory1.createProductB();productA1.doSomething();productB1.doSomething();AbstractFactory factory2 = new ConcreteFactory2();AbstractProductA productA2 = factory2.createProductA();AbstractProductB productB2 = factory2.createProductB();productA2.doSomething();productB2.doSomething();}
}

相关文章:

设计模式(工厂模式,模板方法模式,单例模式)

单例模式&#xff1a; 确保一个类只有一个实例&#xff0c;并提供全局访问点。 单例模式举例&#xff1a; 配置信息类&#xff1a;用于存储应用程序的全局配置信息&#xff0c;例如数据库连接信息、日志配置等。 日志类&#xff1a;用于记录应用程序运行时的日志信息&#x…...

ES6 对象的新增方法(十四)

1. Object.assign(target, …sources) 特性&#xff1a;将一个或多个源对象的所有可枚举属性复制到目标对象。 用法&#xff1a;用于对象属性的合并。 const obj1 { a: 1, b: 2 }; const obj2 { b: 3, c: 4 }; Object.assign(obj1, obj2);console.log(obj1); // 输出&#…...

Spring Boot 学习总结(34)—— spring-boot-starter-xxx 和 xxx-spring-boot-starter 区别?

一、Spring Starter 简介 Spring Starter 是 Spring Boot 提供的一种便捷方式,帮助开发者快速集成和配置 Spring 应用中所需的依赖。每个 Starter 都是一个预配置的依赖集,可以自动配置应用的一部分或特定功能。这些 Starter 旨在消除手动编写大量样板代码和配置的需求。 1…...

昇思训练营打卡第二十五天(RNN实现情感分类)

RNN&#xff0c;即循环神经网络&#xff08;Recurrent Neural Network&#xff09;&#xff0c;是一种深度学习模型&#xff0c;特别适用于处理序列数据。以下是对RNN的简要介绍&#xff1a; RNN的特点&#xff1a; 记忆性&#xff1a;与传统的前馈神经网络不同&#xff0c;R…...

昇思25天学习打卡营第02天|张量 Tensor

一、什么是张量 Tensor 张量是一种特殊的数据结构&#xff0c;与数组和矩阵非常相似。张量&#xff08;Tensor&#xff09;是MindSpore网络运算中的基本数据结构。 张量可以被看作是一个多维数组&#xff0c;但它比普通的数组更加灵活和强大&#xff0c;因为它支持在GPU等加速…...

权威认可 | 海云安开发者安全助手系统通过信通院支撑产品功能认证并荣获信通院2024年数据安全体系建设优秀案例

近日&#xff0c;2024全球数字经济大会——数字安全生态建设专题论坛&#xff08;以下简称“论坛”&#xff09;在京成功举办。由全球数字经济大会组委会主办&#xff0c;中国信息通信研究院及公安部第三研究所共同承办&#xff0c;论坛邀请多位专家和企业共同参与。 会上颁发…...

24.7.10|暑假-数组题目:实现整数的数字反转【学习记录】

1、题目&#xff1a; 32位有符号整数&#xff0c;将整数每位上的数字进行反转 输入&#xff1a;123 输出&#xff1a;321 输入&#xff1a;-123 输出&#xff1a;-321 输入&#xff1a;120 输出&#xff1a;21 &#xff01;&#xff09; 问题 怎么把整数转换成字符串&#xff…...

【ceph】ceph集群-添加/删除mon

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…...

Django ORM中的Q对象

Q 对象在 Django ORM 中用于构建复杂的查询条件&#xff0c;特别是当你需要使用逻辑运算符&#xff08;如 AND、OR、NOT&#xff09;时。以下是一些使用 Q 对象进行复杂查询的实际例子。 Q对象使用 模型 假设我们有一个包含员工信息的模型 Employee&#xff1a; from djang…...

相控阵雷达原理详解

相控阵&#xff0c;即相位控制阵列&#xff0c;通过控制阵列各个单元的馈电相位来改变波束指向。 相控阵雷达的原理可以清晰地归纳为以下几点&#xff1a; 1. 基本构成&#xff1a; - 相控阵雷达&#xff0c;即相位控制电子扫描阵列雷达&#xff08;Phased Array Radar, PAR&a…...

算法项目报告:物流中的最短路径问题

问题描述 物流问题 有一个物流公司需要从起点A到终点B进行货物运输&#xff0c;在运输过程中&#xff0c;该公司需要途径多个不同的城市&#xff0c;并且在每个城市中都有一个配送站点。为了最大程度地降低运输成本和时间&#xff0c;该公司需要确定经过哪些配送站点&#xff…...

linux中 crontab 定时器用法

*/10 * * * * python3 /home/code/haha2.py Crontab 当然&#xff0c;以下是一个简短的博客&#xff0c;介绍了 Cron 和 Crontab 的用法&#xff1a; --- # 简介&#xff1a;使用 Cron 和 Crontab 在 Linux 中进行定时任务调度 在 Linux 系统中&#xff0c;Cron 是一个用于…...

java算法day16

java算法day16 112 路径总和404 左叶子之和513 找树左下角的值 112 路径总和 题型判定为自顶向下类型&#xff0c;并且为路径和类型。 那就套模板。 自顶向下就是从上到下处理&#xff0c;那么就是前序遍历的思想。 class Solution {boolean res false;public boolean hasP…...

华为HCIP Datacom H12-821 卷41

1.多选题 以下关于BGP Atomic_Aggregate和Aggregator的描述&#xff0c;正确的是哪些项? A、Aggregator属性属于可选过渡属性 B、Atomic_Aggregate属于公认任意属性 C、收到携带Atomic_Aggregate属性的路由表示这条路由不能再度明细化 D、 Agregator表示某条路由可能出现…...

【React Hooks原理 - forwardRef、useImperativeHandle】

概述 上文我们聊了useRef的使用和实现&#xff0c;主要两个用途&#xff1a;1、用于持久化保存 2、用于绑定dom。 但是有时候我们需要在父组件中访问子组件的dom或者属性/方法&#xff0c;而React中默认是不允许父组件直接访问子组件的dom的&#xff0c;这时候就可以通过forwa…...

用于可穿戴传感器的人类活动识别、健康监测和行为建模的大型语言模型

这篇论文题为《用于可穿戴传感器的人类活动识别、健康监测和行为建模的大型语言模型&#xff1a;早期趋势、数据集和挑战的综述》&#xff0c;由埃米利奥费拉拉&#xff08;Emilio Ferrara&#xff09;撰写。论文主要内容如下&#xff1a; 摘要 可穿戴技术的普及使得传感器数…...

react事件绑定

react基础事件绑定 function passwordChange(e){console.log(e.target.value); } function usernameChange(e){console.log(e.target.value); }function App() {return (<div><input type"text" placeholder请输入用户名onChange{usernameChange}/><i…...

spring框架之AOP注解方式(java代码实例)

目录 半注解形式&#xff1a; 业务层接口实现类&#xff1a; 编写切面类&#xff1a; 在配置文件里面唯一需要加的&#xff1a; 测试类&#xff1a; 全注解形式&#xff1a; 不要配置文件&#xff0c;改为配置类&#xff1a; 同样的业务层接口实现类&#xff1a; 同样的…...

windows下gcc编译C、C++程序 MinGW编译器

文章目录 1、概要2、MinGW安装2.1 编译器下载2.2 编译器安装2.3 设置环境变量2.4 查看gcc版本信息 3、编译C、C程序3.1 编写Hello World.c3.2 编译C程序3.3 运行程序3.4 编译C程序 1、概要 GCC原名为GNU C语言编译器&#xff08;GNU C Compiler&#xff09;&#xff0c;只能处…...

uniapp启动图延时效果,启动图的配置

今天阐述uniapp开发中给启动图做延迟效果&#xff0c;不然启动图太快了&#xff0c;一闪就过去了&#xff1b; 一&#xff1a;修改配置文件&#xff1a;manifest.json "app-plus" : {"splashscreen" : {"alwaysShowBeforeRender" : false,"…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...