常见设计模式

设计模式

Version1.0.1

1. 设计模式的类型

  1. 创建型模式
    • 提供一种在创建对象的同时隐藏创建逻辑的方式。使得程序在判断针对某个实例需要创建哪些对象时更加灵活

    • 工厂模式,单例模式,原型模式

  2. 结构型模式
    • 关注对象之间的组合和关系,旨在解决如何构建灵活且可复用的类和对象结构

    • 适配器模式,组合模式,桥接模式

  3. 行为型模式
    • 关注对象之间的通信和交互,旨在解决对象之间的责任分配和算法的封装

    • 责任链模式,命令模式,策略模式

2. 创建型模式

单例模式

--单例模式是一种创建型模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。

意图

确保一个类只有一个实例,并提供一个全局访问点来访问该问题实例

主要解决

频繁创建和销毁全局使用的类实例问题

关键代码

构造函数是私有的

实例

  • 一个班级只有一个班主任

  • 设备管理器设计为单例模式,例如两台打印机,避免同时打印同一份文件

  • Windows在多进程多线程环境下操作文件时,避免多个进程或线程操作一个文件,需要通过唯一实例进行处理

优点

  • 内存中只有一个实例,减少内存开销。尤其是频繁创建和销毁实例时

  • 避免资源的多重占用

缺点

  • 没有接口,不能继承
  • 与单一职责原则冲突,一个类应该只关系内部逻辑,而不关注实例方式

使用场景

  • 生成唯一序列号

  • WEB中的计数器,避免每次刷新都在数据库中增加记数,先缓存起来

  • 创建消耗资源过多的对象,如I/O与数据库连接等。

注意事项

  • 线程安全:getInstance()方法中需要使用同步锁synchronized(Singleton.class)防止多线程同时进入造成实例被多次创建。

  • 延迟初始化:实例在第一次调用getInstance()方法时创建

  • 序列化和反序列化:重写readResolve方法以确保反序列化时不会创建新的实例。

  • 反射攻击:在构造函数中添加防护代码,防止通过反射创建新实例

  • 类加载器问题:注意复杂类加载环境可能会导致的多个实例问题

实现

  创建一个SingleObject类。SingleObject类有它的私有构造函数和本身的一个静态实例

  SingleObject类提供一个静态方法,供外界获取它的静态实例。SingletonPatternDemo类使用SingleObject类来获取SingleObjext对象

public class SingleObject {
  //创建SingleObect的一个对象
  private static SingleObject instance = new SingleObject();
  
  // 让构造函数为private,这样类不会被实例化
  private SingleObject (){};
  
  // 获取唯一可用的对象
  public static SingleObject getInstance(){
    return instance;
  }

  public void showMessage(){
    System.out.println("Hello World");
  }
}
// SingletonPatternDemo.java

public class SingletonPatternDemo{
  public static void main(String[] args){
    
    // 获取唯一可用的对象
    SingleObject object = SingleObject.getInstance();
    
    // 显示消息
    object .showMwssage();
  }

}

实现方式

1. 懒汉式,线程不安全

Lazy初始化

多线程不安全

实现难度:易

描述:基本的实现方式,最大的问题是不支持多线程,因为没有加synchronized,这种方式lazy loading明显,不要求线程安全,在多线程不能正常工作

public class Singleton{
  private static Singleton instance;

  private Singleton(){}

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

2. 懒汉式,线程安全

Lazy初始化

多线程安全

实现难度:易

描述:具备很好的lazy loading,能够在多线程中工作,但效率很低。

优点:第一次调用才初始化,避免内存浪费

缺点:必须加锁synchronized才能保证单例,但加锁影响效率

public class Singleton{
  private static Singleton instance;

  private Singleton(){}

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

3. 饿汉式

Lazy未初始化

多线程安全

实现难度:易

描述:这种方式比较常见,但容易产生垃圾对象

优点:没有加锁,执行效率高

缺点:类加载时就初始化,浪费内存

它是居于classloader机制避免多线程同步的问题,不过instance在类加载时就实例化。

public class Singleton{
  private static Singleton instance = new Singleton;

  private Singleton(){}

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

4. 双重校验锁(DCL--double checked locking)

Lazy初始化

多线程安全

实现难度:较为复杂

描述:采用双锁机制,安全且在多线程情况下保持高性能

public class Singleton{
  private volatile static Singleton singleton;

  private Singleton(){}

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

posted on 2024-06-11 15:58  强K  阅读(4)  评论(0编辑  收藏  举报