设计模式


单例模式

  1. 饿汉式(静态常量);
  2. 饿汉式(静态代码块);
  3. 懒汉式(线程不安全);
  4. 懒汉式(线程安全,同步方法);
  5. 懒汉式(线程安全,同步代码块);
  6. 双重检查;
  7. 静态内部类;
  8. 枚举

推荐使用:枚举、静态内部类、双重检查、饿汉式(可能造成浪费)

饿汉式

静态常量

//饿汉式(静态常量)
class Singleton {
    //1、构造器私有化,外部不能new
    private Singleton() {

    }
    //2、本类内部创建对象实例
    private final static Singleton instance = new Singleton();
    //3、提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance() {
        return instance;
    }
}

设计了一个私有静态的final对象,对外开放一个接口返回这个对象

静态代码块

class Singleton {
    //1、构造器私有化,外部不能new
    private Singleton() {

    }

    //2、静态代码块
    private static Singleton instance;

    static {
        instance = new Singleton();
    }

    //3、提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance() {
        return instance;
    }
}

把新建对象放在一个静态的代码块里

优点:简单,类加载就完成实例化,避免线程同步问题

缺点:类加载就完成实例化,回到是内存浪费

懒汉式

//懒汉式(线程不安全)
class Singleton {
    private static Singleton instance;

    private Singleton() {

    }

    //提供一个静态的公有方法,当使用到该方法时,才去创建instance
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点:起到了懒加载的效果,但是只能在单线程下使用;

缺点:如果在多线程下,一个线程进入了if(singleton==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。

//懒汉式(线程安全,同步方法)
class Singleton {
    private static Singleton instance;

    private Singleton() {

    }

    //提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

synchronized加在方法上

优点:加了synchronized解决线程安全问题

缺点:效率低

//懒汉式(线程安全,同步代码块)
class Singleton {
    private static Singleton instance;

    private Singleton() {

    }

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

与上面一种方法的区别是它把synchronized关键字放在了代码块

缺点:看似安全实则不安全:进入if后可能有其他线程也进入if

双重检查(重点)

public class SingletonTest {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2);
    }
}

//双重检查
class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
    }

    //提供一个静态的公有方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

volatile防止指令重排,方法上加synchronized,执行两次if (instance == null),第二次之前先执行synchronized

静态内部类

//静态内部类
class Singleton {

    private Singleton() {
    }

    //写一个静态内部类,该类中有一个静态属性Singleton
    private static class singleInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    //提供一个静态的公有方法,直接返回对象
    public static synchronized Singleton getInstance() {
        return singleInstance.INSTANCE;
    }
}
  • 静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,会装载SingletonInstance类,从而完成Singleton的实例化;
  • 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的;

枚举

public class SingletonTest8 {
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance == instance2);
        instance.sayOK();
    }
}
//使用枚举,可以实现单例
enum Singleton {
    INSTANCE;//属性

    public void sayOK() {
        System.out.println("ok");
    }
}

工厂模式

简单工厂模式

不需要自己new对象,使用factory创建

工厂方法模式

抽象工厂模式

适配器模式

假设存在三个对象:Computer(想上网,没有网口),Usb(网线接口转换为Usb),Online(网线)

类适配器

继承:Usb继承Online,Computer调用Usb

对象适配器

组合:Usb中创建Online对象,Computer调用Usb

代理模式

静态代理

定义接口

定义被代理对象实现接口

定义代理对象,代理对象中实现被代理对象

调用代理对象的方法调用被代理对象

动态代理

JDK代理

装饰模式


评论
  目录