目录
动态代理模式(基于接口:jdk动态代理;基于类:cglib动态代理):
Java设计模式是一套在Java程序设计中经过反复使用、多数人知晓的、代码设计经验的总结。它提供了一种框架和结构,旨在帮助开发者更好地理解和设计复杂的系统。设计模式不仅仅是一种语法规则,更是一种思想和方法论,能够帮助开发者更好地分析、设计和实现软件系统,确保代码的重用性、可维护性和可扩展性。这些模式通常被分为创建型模式、结构型模式和行为型模式,每种模式都针对特定的设计问题提供了标准的解决方案。
设计模式共有23种,也可称为GOF23
下面我分次来介绍几种常见的设计模式:
单例模式(重点,常用)
饿汉式: (一上来就把对象加载啦,可能会浪费内存空间)
大致包括:私有的构造器;static final 且 私有 的new对象; public的访问器 返回对象;
(new对象时的static是因为静态方法里只能调用静态属性,final修饰类属性是防止二次改变指向)
懒汉式: (用的时候才加载对象)
(懒汉式有很多 :多线程不安全的懒汉式,多线程安全的懒汉式(性能不够高),双重检测锁的懒汉式(多线程安全+高性能))
双重检测锁懒汉式:
私有构造器; volatile锁防止指令重排序 保证原子性操作;双重检验锁 ,保证高性能
多线程、高并发场景下更加安全
详细解析:
java
public class Singleton {
private volatile static Singleton singleton; //私有属性无法直接读到,
//这个volatile防止指令重排序,第一个线程创建成功但是未完全转为非空,第六个以后的线程会进入第一个if语句,会很麻烦
private Singleton (){} //构造方法私有 是防止new新对象
//每个线程通过这个公有方法来获取对象,相当于一个访问器
public static Singleton getSingleton() {
//这里必须是静态方法,防止能new出来对象(与单例模式相矛盾)
//静态方法中操作变量也必须是静态的(故上面的唯一变量对象是静态的),否则不能在这个静态方法中调用它
//(因为静态方法里面无法操作全局的非静态变量)
if (singleton == null) { //第一次假设5个线程通过了这条if语句,当这5个执行完之后,6、7、8个再进来时会被这个if语句拦截,直接return最初创建的新对象
//多线程调用的情况下,如果是空的话,先锁起来,只允许一个线程创建对象,否则多线程同时拷贝调用这个方法,就创建了多个对象
synchronized (Singleton.class) { //多线程竞争这个锁,进来的只有一个,其余竞争失败线程进入阻塞队列
if (singleton == null) { //第一个线程创建完对象后,singleton 不为空,第一个阻塞队列中的线程(假设2、3、4、5线程)再进来时被这条if语句拦截,故不能再次创建,此时可以直接return一个对象(第一个线程创建的)
singleton = new Singleton();
} // 进来的第一个线程成功创建了对象,然后执行完毕释放锁;原阻塞队列的其他线程再来竞争第一个锁
}
}
return singleton;
}
}
工厂模式
**作用:**创建者和调用者分离
核心本质:
- 实例化对象不使用new,用工厂方法代替
- 将选择实现类,创建对象的统一管理和控制。从而将调用者跟我们的实现类解耦。
常见工厂模式:
简单工厂模式:
使用一个单独的工厂类来创建不同的对象,根据传入的参数判断创建哪种类型的对象。
工厂方法模式:每个人都有自己的工厂(工厂类变多)
定义了一个创建对象的(工厂)接口,但由子类决定实例化哪个类(需要哪个就实例化哪个实现类)。
代理模式:(SpringAOP的底层原理)
静态代理模式:(写死一个代理类Proxy)
最终还是要new一个固定的代理类,直接面向代理类来操作
动态代理模式(基于接口:jdk动态代理;基于类:cglib动态代理):
可以动态生成代理类,不把代理类写死,只写一个代理角色(动态生成代理类)
大致过程:
首先有原接口userService和原接口实现类userServiceImpl;
然后有一个类(实现InvocationHandler接口)可以自动生成代理类。在这个类里面:
1、加上被代理的接口,并实现set方法
2、新建一个方法体 return一个 Proxy.newProxyInstance(三个参数);
三个参数分别为:类加载,代理的哪个接口,this(InvocationHandler的实现类)
这个方法体的作用:得到代理类
3、实现InvocationHandler接口的invoke方法,处理代理的实例,并返回结果(这里是反射的知识)三个参数:调用方法的对象实例,要调用的方法的名称,实际传递给方法的参数值
再来一个类:
new一个真实的最原来的类,例:userServiceImpl
new一个代理角色(上一步创建的那个类)假设名字为pih
pih.set方法(要代理的对象,传入的是接口)
pih.getProxy();动态生成代理类,用proxy来接收
proxy.query(); 用代理类来调用原来类(userServiceImpl)的方法