Java设计模式学习
参考:图灵学院设计模式郭嘉老师
一、单例设计模式
Singleton 知识点:
1.模式定义/应用场景/类图分析
2.字节码知识/字节码指令重排序
3.类加载机制
4.JVM序列化机制
5.单例模式在Spring框架 & JDK源码中的应用
模式定义:
保证一个类只有一个实例,并且提供一个全局访问点
场景:
重量级的对象,不需要多个实例,如线程池,数据库连接池。
1.懒汉模式:延迟加载, 只有在真正使用的时候,才开始实例化。
-
1)线程安全问题
-
2)double check 加锁优化
-
3)编译器(JIT),CPU 有可能对指令进行重排序,导致使用到尚未初始化的实例,可以通过添加volatile 关键字进行修饰,对于volatile 修饰的字段,可以防止指令重排。
class LazySingleton{
private volatile static LazySingleton instance;
private LazySingleton(){
}
public static LazySingleton getInstance() {
if (instance==null){
synchronized (LazySingleton.class){
if (instance==null){
instance=new LazySingleton();
// 字节码层
// JIT , CPU 有可能对如下指令进行重排序
// 1 .分配空间
// 2 .初始化
// 3 .引用赋值
// 如重排序后的结果为如下17 // 1 .分配空间
// 3 .引用赋值 如果在当前指令执行完,有其他线程来获取实例,将拿到尚未初始化好的
实例
// 2 .初始化
}
}
}
return instance;
}
}
2.饿汉模式:
类加载的 初始化阶段就完成了 实例的初始化 。本质上就是借助于jvm类加载机制,保证实例的唯一性(初始化过程只会执行一次)及线程安全(JVM以同步的形式来完成类加载的整个过程)。
类加载过程:
-
1,加载二进制数据到内存中, 生成对应的Class数据结构,
-
2,连接: a. 验证, b.准备(给类的静态成员变量赋默认值),c.解析
-
3,初始化: 给类的静态变量赋初值
只有在真正使用对应的类时,才会触发初始化 如(当前类是启动类即main函数所在类,直接进行new 操作,访问静态属性、访问静态方法,用反射访问类,初始化一个类的子类等.)
// 饿汉模式
class HungrySingleton{
private static HungrySingleton instance=new HungrySingleton();
private HungrySingleton(){
}
public static HungrySingleton getInstance() {
return instance;
}
}
3.静态内部类
1).本质上是利用类的加载机制来保证线程安全
2).只有在实际使用的时候,才会触发类的初始化,所以也是懒加载的一种形式。
class InnerClassSingleton{
private static class InnerClassHolder{
private static InnerClassSingleton instance= new InnerClassSingleton();
}
private InnerClassSingleton(){
}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
}
4.反射攻击实例:
Constructor<InnerClassSingleton> declaredConstructor = InnerClassSingleton.class.getDeclaredConstructor();
declaredConstructor.setAccessible( true );
InnerClassSingleton innerClassSingleton=declaredConstructor.newInstance();
InnerClassSingleton instance=InnerClassSingleton.getInstance();
System.out.println(innerClassSingleton==instance);
静态内部类防止反射破坏
class InnerClassSingleton {
private static class InnerClassHolder{
private static InnerClassSingleton instance= new InnerClassSingleton();
}
private InnerClassSingleton(){
if (InnerClassHolder.instance!=null){
throw new RuntimeException( " 单例不允许多个实例 " );
}
}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
}
5.枚举类型
1)天然不支持反射创建对应的实例,且有自己的反序列化机制
2)利用类加载机制保证线程安全
public enum EnumSingleton {
INSTANCE;
public void print(){
System.out.println(this.hashCode());
}
}
6.序列化
1)可以利用 指定方法来替换从反序列化流中的数据 如下
ANY‐ACCESS‐MODIFIER Object readResolve() throws ObjectStreamException;
class InnerClassSingleton implements Serializable{
static final long serialVersionUID = 42L;
private static class InnerClassHolder{
private static InnerClassSingleton instance= new InnerClassSingleton();
}
private InnerClassSingleton(){
if (InnerClassHolder.instance!=null){
throw new RuntimeException( " 单例不允许多个实例 " );
}
}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
Object readResolve() throws ObjectStreamException{
return InnerClassHolder.instance;
}
}
源码中的应用
// Spring & JDK
java.lang.Runtime
org.springframework.aop.framework.ProxyFactoryBean
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
org.springframework.core.ReactiveAdapterRegistry
// Tomcat
org.apache.catalina.webresources.TomcatURLStreamHandlerFactory
// 反序列化指定数据源
java.util.Currency
二、工厂方法模式
Factory Method 模式定义:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使得一个类的实例化延迟到子类。
简单工厂:
class SimpleFactory {
public static Product createProdcut(String type) {
if (type.equals( "0" )) {
return new ProductA();
} else if (type.equals( "1" )) {
return new ProductA1();
} else {
return null;
}
}
}
工厂方法:
// 稳定接口
interface Product {
public void method1();
}
// 具体实现
class ProductA implements Product {
public void method1() {
System.out.println( "ProductA.method1 executed. " );
}
}
class ProductA1 implements Product {
public void method1() {
System.out.println( "ProductA1.method1 executed. " );
}
}
abstract class Application {
abstract Product createProduct();
Product getObject() {
Product product=createProduct();
// ...
// ...
return product;
}
}
// 工厂方法具体实现类
class ConcreteProductA extends Application {
@Override
Product createProduct() {
// ....
return new ProductA();
}
}
class ConcreteProductA1 extends Application {
@Override
Product createProduct() {
//...
return new ProductA1();
}
}
应用场景
- 1.当你不知道使用对象的确切类型的时候
- 2.当你希望为库或框架提供扩展其内部组件的方法时
主要优点:
- 1.将具体产品和创建者解耦
- 2.符合单一职责原则
- 3.符合开闭原则
源码中的应用:
// java api
// 静态工厂方法
Calendar.getInstance()
java.text.NumberFormat.getInstance()
java.util.ResourceBundle.getBundle()
// 工厂方法
java.net.URLStreamHandlerFactory
javax.xml.bind.JAXBContext.createMarshaller