我梦笔记我梦笔记
Home
Home
  • MySQL
  • Java
  • JVM (黑马)
  • Spring
  • SpringBoot
  • Redis
  • 数据结构
  • 设计模式
  • Linux
  • Nginx
  • VUE.JS
  • Emby 伪站破解认证

设计模式

单例模式

饿汉式静态常量

class Singleton {

    private Singleton(){
    }

    private final static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
}

饿汉式静态代码块

class Singleton {

    private Singleton(){
    }

    private static Singleton instance;

    static {
        instance = new Singleton();
    }

    public static Singleton getInstance() {
        return instance;
    }
}

以上两种写法的优缺点一致:

优点:这两种写法比较简单,就是在类装载的时候完成实例化,避免了线程同步问题。

缺点:没有达到懒加载的效果,有可能会造成内存空间的浪费。

懒汉式(线程不安全)

class Singleton {

    private Singleton(){
    }

    private static Singleton instance;

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

起到了懒加载的效果,但只能在单线程环境下使用,多线程环境下可能会产生多个实例。在实际开发当中,不要使用这种方式。

懒汉式(线程安全,同步方法)

class Singleton {

    private Singleton(){
    }

    private static Singleton instance;

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

有点:解决了线程不安全的问题。

缺点:效率太低了,每个线程想获得类实例的时候都要执行一次同步方法。在实际开发中不推荐使用。

懒汉式(线程安全,同步代码,双重检查)

class Singleton {

    private Singleton(){
    }

    /**
     * 加入volatile,保证线程间可见性
     */
    private static volatile Singleton instance;

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

双重检查是多线程开发中常使用到的,这样实例化的代码就只需要执行一次,避免产生多个实例。而且线程安全,懒加载,效率较高。实际开发中,推荐使用这种单例设计模式。

懒汉式(静态内部类)

class Singleton {

    private Singleton(){
    }

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

采用类装载机制来保证初始化实例时只有一个线程。

静态内部类在外部类被装载时并不会立即初始化,而是在需要时才会装载静态内部类,达到了懒加载的效果。

而且类的静态属性只会在第一次装载类的时候初始化,所以是JVM帮我们保证了线程的安全性,在初始化时,别的线程是无法进入。

总结:避免了线程不安全,利用静态内部类的特点实现懒加载,效率高。推荐使用。

懒汉式(枚举)

public class Singleton07 {

    public static void main(String[] args) {
        Singleton singleton1 = Singleton.INSTANCE;
        Singleton singleton2 = Singleton.INSTANCE;
        System.out.println(singleton1 == singleton2);
        singleton1.sayhello();
    }

}

enum Singleton {
    
    INSTANCE;
    
    public void sayhello() {
        System.out.println("hello");
    }
}

借助JDK1.5中添加的枚举来实现单例模式,不仅能避免多线程同步问题,还能防止反序列化重新创建新的对象。

这种方式也是一个Java作者提倡的。推荐使用。

策略模式

封装不同地执行策略或者说方式,减少 if else 的使用。

策略的三大角色

  • 环境角色类(策略的对象):比如价格有很多种计算方式,一种方式就是一种策略,价格就是策略的最终对象。(谁拥有策略)
  • 抽象策略角色(策略的抽象类):一般是接口或者抽象类。
  • 具体策略角色(策略实现类):包装了某一种策略的具体实现(行为)。

使用场景

假设现在要设计一个贩卖各类书籍的电子商务网站的购物车系统。一个最简单的情况就是把所有货品的单价乘上数量,但是实际情况肯定比这要复杂。比如,本网站可能对所有的高级会员提供每本20%的促销折扣;对中级会员提供每本10%的促销折扣;对初级会员没有折扣。

根据描述,折扣是根据以下的几个算法中的一个进行的:

算法一:对初级会员没有折扣。

算法二:对中级会员提供10%的促销折扣。

算法三:对高级会员提供20%的促销折扣。

定义一个计算折扣的接口

public interface MemberStrategy {
    /**
     * 计算图书的价格
     * @param booksPrice    图书的原价
     * @return    计算出打折后的价格
     */
    public double calcPrice(double booksPrice);
}

用不同的折扣策略实现该接口

初级会员折扣类

public class PrimaryMemberStrategy implements MemberStrategy {

    @Override
    public double calcPrice(double booksPrice) {
        
        System.out.println("对于初级会员的没有折扣");
        return booksPrice;
    }
}

中级会员折扣类

public class IntermediateMemberStrategy implements MemberStrategy {

    @Override
    public double calcPrice(double booksPrice) {

        System.out.println("对于中级会员的折扣为10%");
        return booksPrice * 0.9;
    }
}

高级会员折扣类

public class AdvancedMemberStrategy implements MemberStrategy {

    @Override
    public double calcPrice(double booksPrice) {
        
        System.out.println("对于高级会员的折扣为20%");
        return booksPrice * 0.8;
    }
}

策略对象类(环境角色)

public class Price {
    //持有一个具体的策略对象
    private MemberStrategy strategy;
    /**
     * 构造函数,传入一个具体的策略对象
     * @param strategy    具体的策略对象
     */
    public Price(MemberStrategy strategy){
        this.strategy = strategy;
    }
    
    /**
     * 计算图书的价格
     * @param booksPrice    图书的原价
     * @return    计算出打折后的价格
     */
    public double quote(double booksPrice){
        return this.strategy.calcPrice(booksPrice);
    }
}

客户端调用

public class Client {

    public static void main(String[] args) {
        //选择并创建需要使用的策略对象
        MemberStrategy strategy = new AdvancedMemberStrategy();
        //创建环境
        Price price = new Price(strategy);
        //计算价格
        double quote = price.quote(300);
        System.out.println("图书的最终价格为:" + quote);
    }

}

策略模式的优缺点

优点:可以避免使用多重条件(if-else)语句。

缺点:

  • 客户端必须要知道所有策略,并自行决定使用哪一种策略。
  • 如果策略比较多,对象的数量也会很多。
最近更新:: 2026/1/6 22:21
Contributors: womeng
Prev
数据结构
Next
Linux