了解单例模式,工厂模式(简单易懂)

文章目录

  • 单例模式
    • 饿汉模式
    • 懒汉模式
    • 对比
  • 工厂模式
    • 简单工厂模式(Simple Factory Pattern)
    • 工厂方法模式(Factory Method Pattern)
    • 抽象工厂模式(Abstract Factory Pattern)
    • 对比

单例模式

  • 什么是单例? 系统运行期间有且仅有一个实例。
  • 为什么要有单例?系统中的一些对象只需要初始化一次即可,例如:KTV中的播放器或者初始化系统参数
  • 单例模式的要求:
    1. 一个类只有一个实例 只提供私有的构造器。
    private SingletonClass(){  }  
    
    1. 必须自己创建这个实例 定义该类的静态私有对象。
    private static SingletonClass single; 
    
    1. 必须自己向系统提供这个实例。 创建一个公共的静态方法,返回这个实例。
    public static SingletonClass getSingleton(){if(single==null){initSingleton();}return single;
    }
    

饿汉模式

不管你用不用我都给你创建这个实例。(官方语言:在类加载的时候创建这个实例)。 天然线程安全的,每个类中获取这个对象的耗时基本一样

下面是饿汉模式,使用静态内部类实现延迟加载。

public class SingleTon {private SingleTon() {}private static SingleTon singleTon;// 静态内部类public static class SingletonHelper{private static final SingleTon INSTANCE = new  SingleTon();}public static SingleTon getSingleTon() {singleTon = SingletonHelper.INSTANCE;return singleTon;}}

懒汉模式

在你调用的时候才创建这个实例。不是线程安全,第一次获取此对象会耗时较多

  • 线程安全问题
  • double check 加锁优化
  • 编译器(JIT),CPU有可能对指令执行重新排序,导致使用到尚未初始化的实例(nullpointException),可以通过添加volatile关键字进行修饰,对于volatile修饰的字段,可以防止指令重排。
/*** 手写一个单例模式*/
public class SingletonClass {// 1.私有化构造方法,收回创建实例的权限private SingletonClass(){}// 2.自己声明这个实例对象private volatile static SingletonClass singletonClass;// 3.向系统提供一个公共的方法,获取这个实例public static SingletonClass getInstance(){if(singletonClass==null){ // 为空才加同步锁,锁的范围越小越好synchronized (SingletonClass.class){if(singletonClass==null){ // 判断是否为空,防止实例化两次singletonClass = new SingletonClass();// 字节码 其中2和3可能存在重排的问题,如果3在前,在多线程的情况下会出现空指针// 1.分配空间// 2.初始化// 3.引用赋值}}}return singletonClass;}}

对比

  1. 线程安全:饿汉式天生就是线程安全的,懒汉式本身是非线程安全的。
  2. 资源加载和性能:饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。

工厂模式

  1. 什么是工厂? 将对象的创建过程封装在一个工厂类中,通过调用工厂类的方法来获取对象实例,而不需要直接使用new关键字来创建对象
  2. 为什么要有工厂模式? 工厂模式能够提供更好的代码组织结构、更好的封装性、更好的可扩展性和更好的解耦性,从而提高了代码的质量和可维护性
  3. 工厂模式的要求
  • 抽象产品:定义产品的共同接口或抽象类,描述产品的特征和行为。
  • 具体产品:实现抽象产品接口或继承抽象产品类,是工厂创建的目标对象。
// 抽象产品接口
public interface Product {void operation1();void operation2();
}// 具体类A
public class ConcreteProductA implements Product {@Overridepublic void operation1() {// 具体类A的操作1}@Overridepublic void operation2() {// 具体类A的操作2}
}// 具体类B
public class ConcreteProductB implements Product {@Overridepublic void operation1() {// 具体类B的操作1}@Overridepublic void operation2() {// 具体类B的操作2}
}
  • 抽象工厂:定义工厂的共同接口或抽象类,描述创建产品的方法。
  • 具体工厂:实现抽象工厂接口或继承抽象工厂类,负责实际创建产品的类。
  • 客户端:使用工厂创建产品的代码,通过工厂接口来创建所需的产品对象。
# 定义抽象工厂接口
class AbstractFactory:def create_product_a(self):passdef create_product_b(self):pass# 实现具体的工厂类
class ConcreteFactory1(AbstractFactory):def create_product_a(self):return ProductA1()def create_product_b(self):return ProductB1()class ConcreteFactory2(AbstractFactory):def create_product_a(self):return ProductA2()def create_product_b(self):return ProductB2()# 定义产品接口
class AbstractProductA:def do_something(self):passclass AbstractProductB:def do_something(self):pass# 实现具体类
class ProductA1(AbstractProductA):def do_something(self):print("Product A1")class ProductA2(AbstractProductA):def do_something(self):print("Product A2")class ProductB1(AbstractProductB):def do_something(self):print("Product B1")class ProductB2(AbstractProductB):def do_something(self):print("Product B2")# 客户端代码
def client_code(factory):product_a = factory.create_product_a()product_b = factory.create_product_b()product_a.do_something()product_b.do_something()# 使用具体工厂1
factory1 = ConcreteFactory1()
client_code(factory1)# 使用具体工厂2
factory2 = ConcreteFactory2()
client_code(factory2)

简单工厂模式(Simple Factory Pattern)

简单工厂模式又称为静态工厂模式,它由一个工厂类来负责创建所有的产品对象。客户端只需要通过工厂类来创建产品对象,而不需要直接实例化具体产品类。简单工厂模式的核心是一个工厂类,它包含一个创建产品的方法,根据客户端传入的参数来决定创建哪种产品。

# 定义产品接口
class Product:def show(self):pass# 定义具体类A,实现接口
class ConcreteProductA(Product):def show(self):print("Concrete Product A")# 定义具体类B,实现接口
class ConcreteProductB(Product):def show(self):print("Concrete Product B")# 定义静态工厂类
class StaticFactory:@staticmethoddef create_product(product_type):if product_type == "A":return ConcreteProductA()elif product_type == "B":return ConcreteProductB()else:raise ValueError("Invalid product type")# 客户端代码
if __name__ == "__main__":product_a = StaticFactory.create_product("A")  # 使用静态工厂类创建具体Aproduct_a.show()  # 调用具体A的方法,输出 "Concrete Product A"product_b = StaticFactory.create_product("B")  # 使用静态工厂类创建具体Bproduct_b.show()  # 调用具体B的方法,输出 "Concrete Product B"

工厂方法模式(Factory Method Pattern)

工厂方法模式将具体产品的创建过程延迟到子类中进行,每个具体产品都对应一个具体工厂类。客户端通过调用工厂方法来创建产品对象,工厂方法由子类实现,以创建对应的具体产品对象。

// 抽象类
public abstract class Product {public abstract void use();
}// 具体类A
public class ConcreteProductA extends Product {@Overridepublic void use() {System.out.println("使用具体类A");}
}// 具体类B
public class ConcreteProductB extends Product {@Overridepublic void use() {System.out.println("使用具体类B");}
}// 抽象工厂类
public abstract class Factory {public abstract Product createProduct();
}// 工厂类A
public class ConcreteFactoryA extends Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}// 工厂类B
public class ConcreteFactoryB extends Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}// 客户端代码
public class Client {public static void main(String[] args) {Factory factoryA = new ConcreteFactoryA();Product productA = factoryA.createProduct();productA.use();Factory factoryB = new ConcreteFactoryB();Product productB = factoryB.createProduct();productB.use();}
}

抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口,而无需指定其具体类。抽象工厂模式包含一个抽象工厂接口,定义了用于创建产品对象的方法,具体工厂类实现了抽象工厂接口,并负责创建一系列相关产品。每个具体工厂类都对应于一个产品族,可以创建该产品族的多个产品。

// 定义抽象A
interface AbstractProductA {void operationA();
}// 定义具体A1
class ConcreteProductA1 implements AbstractProductA {public void operationA() {System.out.println("Product A1");}
}// 定义具体A2
class ConcreteProductA2 implements AbstractProductA {public void operationA() {System.out.println("Product A2");}
}// 定义抽象B
interface AbstractProductB {void operationB();
}// 定义具体B1
class ConcreteProductB1 implements AbstractProductB {public void operationB() {System.out.println("Product B1");}
}// 定义具体B2
class ConcreteProductB2 implements AbstractProductB {public void operationB() {System.out.println("Product B2");}
}// 定义抽象工厂
interface AbstractFactory {AbstractProductA createProductA();AbstractProductB createProductB();
}// 定义具体工厂1
class ConcreteFactory1 implements AbstractFactory {public AbstractProductA createProductA() {return new ConcreteProductA1();}public AbstractProductB createProductB() {return new ConcreteProductB1();}
}// 定义具体工厂2
class ConcreteFactory2 implements AbstractFactory {public AbstractProductA createProductA() {return new ConcreteProductA2();}public AbstractProductB createProductB() {return new ConcreteProductB2();}
}// 调用方
public class Client {public static void main(String[] args) {// 创建工厂1AbstractFactory factory1 = new ConcreteFactory1();// 使用工厂1创建A和BAbstractProductA productA1 = factory1.createProductA();AbstractProductB productB1 = factory1.createProductB();productA1.operationA();productB1.operationB();// 创建工厂2AbstractFactory factory2 = new ConcreteFactory2();// 使用工厂2创建A和BAbstractProductA productA2 = factory2.createProductA();AbstractProductB productB2 = factory2.createProductB();productA2.operationA();productB2.operationB();}
}

对比

  • 简单工厂模式适用于对象种类较少且不会频繁变化的情况,工厂方法模式适用于对象种类较多且可能会有新产品增加的情况,抽象工厂模式适用于创建一组相关或相互依赖的产品且可能会有新的产品组合增加的情况。根据具体的需求和场景,选择适合的工厂模式可以提高代码的灵活性和可维护性。
  • 简单工厂模式是通过一个工厂类来创建所有的产品对象,根据不同的参数返回不同的具体产品对象。在多线程环境下,如果多个线程同时调用工厂的创建方法,可能会导致线程安全问题。解决这个问题的一种方式是在工厂类的创建方法上加锁,保证同一时间只有一个线程能够调用该方法。
  • 工厂方法模式将产品的创建延迟到子类中,每个产品有一个对应的工厂类来创建。在多线程环境下,每个线程独立使用各自的工厂类创建产品对象,不存在线程安全问题。不同的线程可以并发调用不同的工厂类创建产品,互不干扰。
  • 抽象工厂模式通过提供一个接口来创建一系列相关或依赖对象的家族,而不需要指定具体的类。在多线程环境下,如果多个线程同时调用不同的具体工厂类创建产品对象,也不存在线程安全问题。不同的线程可以并发调用不同的具体工厂类创建产品,互不干扰。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于模板的大致认识【C++】

文章目录 函数模板函数模板的原理函数模板的实例化模板参数的匹配原则 类模板类模板的定义格式类模板的实例化 非类型模板参数typename 与class模板的特化函数模板特化类模板特化全特化偏特化 模板的分离编译 函数模板 函数模板的原理 template <typename T> //模板参数…

Next.js - Loading UI and Streaming

特殊文件 loading.js 可帮助您使用 React Suspense 创建有意义的加载用户界面。使用此约定&#xff0c;您可以在加载路由段内容时显示来自服务器的即时加载状态。渲染完成后&#xff0c;新的内容会自动切换进来。 即时加载状态 即时加载状态是在导航时立即显示的后备用户界面…

使用Token方式实现用户身份鉴权认证

一、什么是Token&#xff1f; Token&#xff0c;也称为“令牌”&#xff0c;是服务端生成的一串字符串&#xff0c;以作客户端进行请求的一个令牌&#xff0c;当第一次登录后&#xff0c;服务器生成一个Token便将此Token返回给客户端&#xff0c;以后客户端只需带上这个Token前…

【微服务】微服务的概论

微服务&#xff1a;构建面向为了解决这个问题&#xff0c;微服务架构应运而生。本文将向您介绍微服务的概念、优势、实现原理以及应用场景&#xff0c;带您领略微服务在构建面向未来的高效应用中的魅力。 一、微服务的概念和优势 微服务是一种将应用拆分为一系列小型、独立服…

湘潭大学 湘大 XTU OJ 1116 水仙花数 题解(非常详细)

链接 1116 题面 Description 如果一个n位数的每个数位的n次方和就是本身&#xff0c;那么我们称这种数为“水仙花数”。比如371,337313273431 371。现给你一个数&#xff0c;请求这个数是否是水仙花数。 输入 有多组样例。每个样例占一行&#xff0c;为一个整数a&#xff0…

Unity记录4.1-存储-根据关键字加载Tile

文章首发见博客&#xff1a;https://mwhls.top/4810.html。 无图/格式错误/后续更新请见首发页。 更多更新请到mwhls.top查看 欢迎留言提问或批评建议&#xff0c;私信不回。 汇总&#xff1a;Unity 记录 摘要&#xff1a;实现完 Tilemap 地图生成后&#xff0c;实现根据关键字…

智慧充电桩物联网方案架构

智慧充电桩物联网采用“云-管-边-端”的边缘计算物联网架构&#xff0c;融合5G、AI、Wi-Fi 6等技术&#xff0c;实现充电基础设施由数字化向智能化演进。智慧充电桩物联网方案架构设计&#xff0c;如下图所示&#xff1a; 云端&#xff1a; 物联网平台具备广泛协议的南向接入…

【Spring框架】Spring事务的介绍与使用方法

⚠️ 再提醒一次&#xff1a;Spring 本身并不实现事务&#xff0c;Spring事务 的本质还是底层数据库对事务的支持。你的程序是否支持事务首先取决于数据库 &#xff0c;比如使用 MySQL 的话&#xff0c;如果你选择的是 innodb 引擎&#xff0c;那么恭喜你&#xff0c;是可以支持…

Windows使用MobaXterm远程访问ubuntu20.04桌面

参考ubuntu 2020.4 安装vnc 一、脚本文件 remote_setup.sh脚本文件内容&#xff1a; #! /bin/bash #参考链接&#xff1a;https://blog.csdn.net/hailangdeyingzi/article/details/124507304 sudo apt update sudo apt install x11vnc -y sudo x11vnc -storepasswd telpo.12…

【多天线传输技术】迫零检测算法、串行干扰相消算法、排序串行干扰相消算法

clc; clear; close all; len_s100000; % 信号长度 snr0:2:20;%信噪比 len_snrlength(snr); s2_1zeros(1,4); ber_zfzeros(1,len_snr); ber_zf_siczeros(1,len_snr); ber_zf_chsiczeros(1,len_snr); for ii1:len_snrerror_zf20;for i1:len_ssnrandi([0,1],4,1); %产生随机信号mo…

SQL注入之堆叠查询

文章目录 堆叠查询是什么&#xff1f;堆叠查询修改所有用户密码堆叠查询删除数据库恢复数据库 堆叠查询是什么&#xff1f; 在SQL中&#xff0c;分号;是用来表示一条sql语句的结束。试想一下我们在; 结束一个sql语句后继续构造下一条语句&#xff0c;会不会一起执行&#xff1f…

vscode里配置C#环境并运行.cs文件

vscode是一款跨平台、轻量级、开源的IDE, 支持C、C、Java、C#、R、Python、Go、Nodejs等多种语言的开发和调试。下面介绍在vscode里配置C#环境。这里以配置.Net SDK v5.0&#xff0c;语言版本为C#9.0&#xff0c;对应的开发平台为VS2019&#xff0c;作为案例说明。 1、下载vsc…

JavaScript下载excel文件

文章目录 通过链接下载a标签下载方法注意 获取文件流请求体配置下载文件流 总结 通过链接下载 a标签 对于已知地址的目标文件&#xff0c;前端可以使用 a标签 来直接下载&#xff0c;使用a标签下载使用到两个属性 download&#xff1a;下载文件名href&#xff1a;目标文件下…

安卓动态申请权限

我们在使用一些官方app时&#xff0c;刚下载进去之后经常会弹出各种各样的权限获取请求&#xff0c;今天简单学习了下&#xff0c;希望不会误人子弟哈哈哈哈。 一、将需要用到的权限添加到Manifest清单里 <uses-permission android:name"android.permission.WRITE_EXT…

Python3 基础语法

Python3 基础语法 编码 默认情况下&#xff0c;Python 3 源码文件以 UTF-8 编码&#xff0c;所有字符串都是 unicode 字符串。 当然你也可以为源码文件指定不同的编码&#xff1a; # -*- coding: cp-1252 -*- 上述定义允许在源文件中使用 Windows-1252 字符集中的字符编码&…

探索短视频小程序/小年糕

短视频小程序的兴起&#xff0c;为创作者提供了一个全新的平台&#xff0c;让他们能够以更专业的方式展现自己的作品。这种创作形式不仅要求作品内容足够精彩还需要有深度的思考和逻辑性的呈现。本文将探索短视频小程序的专业与深度的创作之道&#xff0c;帮助创作者更好地发挥…

PHP实现每日蛋白质摄入量计算器

1.laravel 路由 //每日蛋白质摄入计算器Route::get(api/protein/intake, FormulaControllerproteinIntakeCal); 2.代码 /*** 每日蛋白质摄入计算器*/public function proteinIntakeCal(){$number intval($this->request(number));$goalFactor array(0.8, 1.16, 0.8, 1.16,…

Shiro学习总结

第一章 入门概述 1.概念 shiro是一个Java安全框架&#xff0c;可以完成&#xff1a;认证、授权、加密、会话管理、与web集成、缓存… 2.优势 ● 易于使用&#xff0c;构建简单 ● 功能全面 ● 灵活&#xff0c;可以在任何应用程序环境中工作&#xff0c;并且不需要依赖它们…

Spring缓存深入解析:@Cacheable的使用详解

摘要&#xff1a;在本文中&#xff0c;我们将深入研究Spring框架中的Cacheable注解。我们会通过详细的Java示例&#xff0c;探讨如何使用这个功能强大的注解来提升应用程序性能。 一、什么是缓存&#xff1f; 在计算机科学中&#xff0c;缓存是一种存储技术&#xff0c;用于保…

LeetCode863. 二叉树中所有距离为 K 的结点(相关话题:深度遍历,广度遍历)

题目描述 给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 k 。 返回到目标结点 target 距离为 k 的所有结点的值的列表。 答案可以以 任何顺序 返回。 示例 1: 输入:root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, k = 2 输出:[7,4,1] 解释…