常见设计模式
设计模式
1. 设计模式的类型
- 创建型模式
-
提供一种在创建对象的同时隐藏创建逻辑的方式。使得程序在判断针对某个实例需要创建哪些对象时更加灵活
-
工厂模式,单例模式,原型模式
-
- 结构型模式
-
关注对象之间的组合和关系,旨在解决如何构建灵活且可复用的类和对象结构
-
适配器模式,组合模式,桥接模式
-
- 行为型模式
-
关注对象之间的通信和交互,旨在解决对象之间的责任分配和算法的封装
-
责任链模式,命令模式,策略模式
-
2. 创建型模式
单例模式
--单例模式是一种创建型模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。
意图
确保一个类只有一个实例,并提供一个全局访问点来访问该问题实例
主要解决
频繁创建和销毁全局使用的类实例问题
关键代码
构造函数是私有的
实例
-
一个班级只有一个班主任
-
设备管理器设计为单例模式,例如两台打印机,避免同时打印同一份文件
-
Windows在多进程多线程环境下操作文件时,避免多个进程或线程操作一个文件,需要通过唯一实例进行处理
优点
-
内存中只有一个实例,减少内存开销。尤其是频繁创建和销毁实例时
-
避免资源的多重占用
缺点
- 没有接口,不能继承
- 与单一职责原则冲突,一个类应该只关系内部逻辑,而不关注实例方式
使用场景
-
生成唯一序列号
-
WEB中的计数器,避免每次刷新都在数据库中增加记数,先缓存起来
-
创建消耗资源过多的对象,如I/O与数据库连接等。
注意事项
-
线程安全:getInstance()方法中需要使用同步锁synchronized(Singleton.class)防止多线程同时进入造成实例被多次创建。
-
延迟初始化:实例在第一次调用getInstance()方法时创建
-
序列化和反序列化:重写readResolve方法以确保反序列化时不会创建新的实例。
-
反射攻击:在构造函数中添加防护代码,防止通过反射创建新实例
-
类加载器问题:注意复杂类加载环境可能会导致的多个实例问题
实现
创建一个SingleObject类。SingleObject类有它的私有构造函数和本身的一个静态实例
SingleObject类提供一个静态方法,供外界获取它的静态实例。SingletonPatternDemo类使用SingleObject类来获取SingleObjext对象
public class SingleObject {
//创建SingleObect的一个对象
private static SingleObject instance = new SingleObject();
// 让构造函数为private,这样类不会被实例化
private SingleObject (){};
// 获取唯一可用的对象
public static SingleObject getInstance(){
return instance;
}
public void showMessage(){
System.out.println("Hello World");
}
}
// SingletonPatternDemo.java
public class SingletonPatternDemo{
public static void main(String[] args){
// 获取唯一可用的对象
SingleObject object = SingleObject.getInstance();
// 显示消息
object .showMwssage();
}
}
实现方式
1. 懒汉式,线程不安全
Lazy初始化
多线程不安全
实现难度:易
描述:基本的实现方式,最大的问题是不支持多线程,因为没有加synchronized,这种方式lazy loading明显,不要求线程安全,在多线程不能正常工作
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
2. 懒汉式,线程安全
Lazy初始化
多线程安全
实现难度:易
描述:具备很好的lazy loading,能够在多线程中工作,但效率很低。
优点:第一次调用才初始化,避免内存浪费
缺点:必须加锁synchronized才能保证单例,但加锁影响效率
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
3. 饿汉式
Lazy未初始化
多线程安全
实现难度:易
描述:这种方式比较常见,但容易产生垃圾对象
优点:没有加锁,执行效率高
缺点:类加载时就初始化,浪费内存
它是居于classloader机制避免多线程同步的问题,不过instance在类加载时就实例化。
public class Singleton{
private static Singleton instance = new Singleton;
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
4. 双重校验锁(DCL--double checked locking)
Lazy初始化
多线程安全
实现难度:较为复杂
描述:采用双锁机制,安全且在多线程情况下保持高性能
public class Singleton{
private volatile static Singleton singleton;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null){
synchronized(Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!