【持续更新】Java设计模式笔记

161 阅读4分钟

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 使得一个类的实例化延迟到子类。

image.png

简单工厂:

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