常用设计模式汇总

一、单例模式

1、类图

 2、时序图

3、实现代码:

package com.example.pattern.Singleton;

public class Singleton {
    private static Singleton instance;
    private Singleton (){}

    // 0、原始写法
    // 这段代码简单明了,而且使用了懒加载模式,
    //但是却存在致命的问题。当有多个线程并行调用 getInstance() 的时候,就会创建多个实例。
    //也就是说在多线程下不能正常工作。
    public static Singleton getInstance() {
        // if 判断与 new 对象 不是原子操作 导致线程安全
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    // 1、懒汉式,线程安全
    // 最简单的方法是将整个 getInstance() 方法设为同步(synchronized
    // 虽然做到了线程安全,并且解决了多实例的问题,但是它并不高效。
    //因为在任何时候只能有一个线程调用 getInstance() 方法。
    public static synchronized Singleton getInstanceForThreadSafe() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    // 2、双重检验锁(double checked locking DCL
    //是一种使用同步块加锁的方法。程序员称其为双重检查锁,因为会有两次检查 instance == null
    //一次是在同步块外,一次是在同步块内。为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if
    private volatile static Singleton instanceDCL; //声明成 volatile
    public static Singleton getSingleton() {
        if (instanceDCL == null) { // 多个线程执行到此处       //Single Checked
            synchronized (Singleton.class) {
                if (instanceDCL == null) {                 //Double Checked
//                    这里也有问题:主要在于instance = new Singleton()这句,
//                    这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。
//                    1、给 instance 分配内存
//                    2、调用 Singleton 的构造函数来初始化成员变量
//                    3、将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)
//                    但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,
//                    最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,
//                    这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。
//                    只需要将 instance 变量声明成 volatile 就可以了。
                    instanceDCL = new Singleton();
                }
            }
        }
        return instanceDCL ;
    }

    // 3、饿汉式 static final field
    // 单例的实例被声明成 static  final 变量了,在第一次加载类到内存中时就会初始化,所以创建实例本身是线程安全的。
    //类加载时就初始化
//    单例会在加载类后一开始就被初始化,即使客户端没有调用 getInstance()方法。
//    饿汉式的创建方式在一些场景中将无法使用:譬如 Singleton 实例的创建是依赖参数或者配置文件的,
//     getInstance() 之前必须调用某个方法设置参数给它,那样这种单例写法就无法使用了。
    private static final Singleton instanceStatic = new Singleton();

    public static Singleton getInstanceStatic(){
        return instanceStatic;
    }

    // 4、静态内部类 static nested class
    // 使用JVM本身机制保证了线程安全问题;由于 SingletonHolder 是私有的,
   // 除了 getInstance() 之外没有办法访问它,因此它是懒汉式的;同时读取实例的时候不会进行同步,没有性能缺陷
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    public static final Singleton getInstanceClass() {
        return SingletonHolder.INSTANCE;
    }

    // 5、枚举 Enum
    // 一般来说,单例模式有五种写法:懒汉、饿汉、双重检验锁、静态内部类、枚举。
//    一般情况下直接使用饿汉式就好了,如果明确要求要懒加载(lazy initialization)会倾向于使用静态内部类,
//    如果涉及到反序列化创建对象时会试着使用枚举的方式来实现单例。




}

  4、测试类:

package com.example.pattern.Singleton;

import org.junit.Test;

import java.util.HashMap;
import java.util.HashSet;

/**
 * 单例模式不同实现方式的测试类
 */
public class SingletonTest {
    final static Integer ThreadCount = 10;
    HashMap<String,Singleton> singletonHashMap = new HashMap<>();


    @Test
    public void test(){
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1);
        System.out.println(singleton2);
        System.out.println(singleton1==singleton2);
    }
    // 0、原始写法 存在线程安全
    @Test
    public void testTheadSafe() throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                Singleton singleton = Singleton.getInstance();
                System.out.println(singleton);
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Singleton singleton = Singleton.getInstance();
                System.out.println(singleton);
            }
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
    }
    // 1、懒汉式,线程安全解决
    @Test
    public void testTheadSafeResolve() throws InterruptedException {
        for (int i=0; i< ThreadCount; i++){
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    Singleton singleton = Singleton.getInstanceForThreadSafe();
                    System.out.println(singleton);
                    singletonHashMap.put(Thread.currentThread().getName(),singleton);
                }
            },"ThreadId="+Thread.currentThread().getName());
            thread.start();
            thread.join();
        }
        HashSet hashSet = new HashSet(singletonHashMap.values());
        if (hashSet.size() != singletonHashMap.values().size() ){
            System.err.println("存在重复的单例对象");
        }else {
            System.out.println("不存在重复的单例对象");
        }
    }

    // 2、双重检验锁(double checked locking DCL
    @Test
    public void testDCL() throws InterruptedException {
        for (int i=0; i< ThreadCount; i++){
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    Singleton singleton = Singleton.getSingleton();
                    System.out.println(singleton);
                    singletonHashMap.put(Thread.currentThread().getName(),singleton);
                }
            },"ThreadId="+Thread.currentThread().getName());
            thread.start();
            thread.join();
        }
        HashSet hashSet = new HashSet(singletonHashMap.values());
        if (hashSet.size() != singletonHashMap.values().size() ){
            System.err.println("存在重复的单例对象");
        }else {
            System.out.println("不存在重复的单例对象");
        }
    }

    // 3、饿汉式 static final field
    @Test
    public void testStatic() throws InterruptedException {
        for (int i=0; i< ThreadCount; i++){
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    Singleton singleton = Singleton.getInstanceStatic();
                    System.out.println(singleton);
                    singletonHashMap.put(Thread.currentThread().getName(),singleton);
                }
            },"ThreadId="+Thread.currentThread().getName());
            thread.start();
            thread.join();
        }
        HashSet hashSet = new HashSet(singletonHashMap.values());
        if (hashSet.size() != singletonHashMap.values().size() ){
            System.err.println("存在重复的单例对象");
        }else {
            System.out.println("不存在重复的单例对象");
        }
    }

    // 4、静态内部类 static nested class
    @Test
    public void testStaticClass() throws InterruptedException {
        for (int i=0; i< ThreadCount; i++){
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    Singleton singleton = Singleton.getInstanceClass();
                    System.out.println(singleton);
                    singletonHashMap.put(Thread.currentThread().getName(),singleton);
                }
            },"ThreadId="+Thread.currentThread().getName());
            thread.start();
            thread.join();
        }
        HashSet hashSet = new HashSet(singletonHashMap.values());
        if (hashSet.size() != singletonHashMap.values().size() ){
            System.err.println("存在重复的单例对象");
        }else {
            System.out.println("【不存在重复的单例对象】");
        }
    }
}

二、代理模式

1、类图

2、时序图

 3、代码实现

//抽象主题
public interface Subject {
    void request();
}

//真实主题
public class RealSubject implements Subject {
    public void request() {
        System.out.println("访问真实主题方法...");
    }
}

//代理对象
public class Proxy implements Subject {
    private RealSubject realSubject;

    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    public void request() {
        preRequest();
        realSubject.request();
        afterRequest();
    }

    public void preRequest() {
        System.out.println("访问真实主题之前的预处理。");
    }

    public void afterRequest() {
        System.out.println("访问真实主题之后的后续处理。");
    }
}

4、测试类


public class ProxyPattern {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Proxy proxy = new Proxy(realSubject);
        proxy.request();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coder_Boy_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值