创建者模式——单例模式

何为创建者模式

创建者模式:创建者模式主要的关注点事怎样创建对象,他的主要特点是“将对象的创建和使用分离”,这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。
创建者模式分为:

  • 单例模式
  • 工厂方法模式
  • 抽象工程模式
  • 原型模式
  • 创建者模式

单例模式

1、单例模式介绍

单例模式(Singleton Pattern)是java中最简单的设计模式之一。这种类型的设计模式属于一种创建类模式,它属于一种创建对象的最佳模式。
这种设计模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了唯一一种访问其对象的方法,可以直接访问,不需要实例化该类的对象。

2、单例模式的结构

单例模式的主要角色如下:

  • 单例类:只能创建一个实例的类
  • 访问类:使用单例模式

3、单例模式的实现

实现模式分为两种:
懒汉式:类加载的时候会导致该单例模式被创建
饿汉式:类加载不会导致该单例模式的对象被创建,而是首次使用该对象的时候被创建

1、饿汉式-方式1(静态变量方式)

package creatorPattren.singleton.demo01;

/**
 *     第一种饿汉式   实现单例模式
 *
 * 使用静态成员变量的方式创建类
 * 向外提供一个公开的获得类的方法
 */
public class Singleton01 {
    //私有化类的构造方法
    private Singleton01() { }

    private static Singleton01 intance = new Singleton01();

    public static Singleton01 getIntance() {
        return intance;
    }
}

2、饿汉式-方式2(加锁静态变量方式)

package creatorPattren.singleton.demo02;

/**
 *     第二种饿汉式   实现单例模式
 *
 * 使用静态成员变量的方式创建类
 * 向外提供一个公开的获得类的方法
 */
public class Singleton02 {
    //私有化类的构造方法
    private Singleton02() { }

    private static Singleton02 intance;

    public static Singleton02 getIntance() {
        //在这里才将类赋值
        if (intance == null) {
            intance = new Singleton02();
        }
        return intance;
    }
}

3、饿汉式-方式3(使用内部类方式)

package creatorPattren.singleton.demo05;

/**
 *     第三种饿汉式   实现单例模式
 *    使用内部类的方式实现
 * 使用静态成员变量的方式创建类
 * 向外提供一个公开的获得类的方法
 */
public class Singleton05 {
    //私有化类的构造方法
    private Singleton05() { }

    private static class getSingleton{
        private static final Singleton05 INSTANCE= new Singleton05();
    }

    public static Singleton05 getIntance() {
        return getSingleton.INSTANCE;
    }
}

4、饿汉式-方式4(使用静态代码块方式)

package creatorPattren.singleton.demo06;

/**
 *     第四种饿汉式   实现单例模式
 *    使用静态代码块的方式实现
 * 使用静态成员变量的方式创建类
 * 向外提供一个公开的获得类的方法
 */
public class Singleton06 {
    //私有化类的构造方法
    private Singleton06() { }

    private static Singleton06 instance;
    static {
        instance = new Singleton06();
    }

    public static Singleton06 getIntance() {
        return instance;
    }
}

5、饿汉式-方式5(使用枚举类型方式)

package creatorPattren.singleton.demo07;

/**
 * 使用枚举类型
 */
public enum Singleton07 {
    INTANCE
}

1、懒汉式-方式1(单个锁)

package creatorPattren.singleton.demo03;

/**
 *     第一种懒汉式   实现单例模式
 *     在第二种的基础上添加了synchronized关键字,解决了保证了多线程情况下依旧可以实现单例模式
 * 使用静态成员变量的方式创建类
 * 向外提供一个公开的获得类的方法
 */
public class Singleton03 {
    //私有化类的构造方法
    private Singleton03() { }

    private static Singleton03 intance;

    public static synchronized Singleton03 getIntance() {
        //在这里才将类赋值
        if (intance == null) {
            intance = new Singleton03();
        }
        return intance;
    }
}

2、懒汉式-方式2(双重锁)

package creatorPattren.singleton.demo04;

/**
 *     第二种懒汉式   实现单例模式
 *     在第三种的基础上改进了锁的机制,改为了双层锁,一定程度上减少了内存的消耗
 * 使用静态成员变量的方式创建类
 * 向外提供一个公开的获得类的方法
 */
public class Singleton04 {
    //私有化类的构造方法
    private Singleton04() { }

    private static Singleton04 intance;

    public static  Singleton04 getIntance() {
        //第一次判断
        if (intance == null) {
            synchronized (Singleton04.class){
//                第二次判断
                if (intance == null) {
                    intance = new Singleton04();
                }
            }

        }
        return intance;
    }
}

4、存在的问题

可以使用序列化和反射的方式破坏单例模式
序列化的方式:

package creatorPattren.singleton.demo08;

import java.io.*;

/**
 * 使用序列化的方式破坏单例模式(枚举类型除外)
 */
public class BreakSingleton {
    public static void main(String[] args) throws Exception {
//        outFileToUSB();
        getFileFromUSB();
        getFileFromUSB();
    }
    public static void outFileToUSB() throws Exception {
        //创建输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\a\\b.txt"));
        //获得对象
        Singleton08 intance = Singleton08.getIntance();
        oos.writeObject(intance);
        System.out.println("执行成功");
    }
    public static void getFileFromUSB() throws Exception {
        //获得输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\a\\b.txt"));
        Singleton08 intance = (Singleton08) ois.readObject();
        System.out.println(intance);
    }

    }

反射的方式

package creatorPattren.singleton.demo08;

import creatorPattren.singleton.demo05.Singleton05;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 使用反射破坏单例模式
 */
public class BreakSingleton02 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1、获得Singleton05的字节码文件
        Class clazz = Singleton05.class;
        //2获得无参构造方法对象
        Constructor constructor = clazz.getDeclaredConstructor();
        //3、取消访问检查
        constructor.setAccessible(true);
        //4、创建对象
        Singleton05 instance = (Singleton05) constructor.newInstance();
        Singleton05 instance1 = (Singleton05) constructor.newInstance();
        System.out.println(instance == instance1);
    }
}

5、解决上面的问题

使用resdResolve方法解决序列化出现的问题,在单例模式的类中加入此代码,返回值为单例模式的类。作用是在反射的时候返回同一个值,而不是新new出来一个

 public Object readResolve(){
        return instance;
    }
package creatorPattren.singleton.demo08;

import java.io.Serializable;

/**
 *     第四种饿汉式   实现单例模式
 *    使用静态代码块的方式实现
 * 使用静态成员变量的方式创建类
 * 向外提供一个公开的获得类的方法
 */
public class Singleton08 implements Serializable {
    //私有化类的构造方法
    private Singleton08() { }

    private static Singleton08 instance;
    static {
        instance = new Singleton08();
    }

    public Object readResolve(){
        return instance;
    }
    public static Singleton08 getIntance() {
        return instance;
    }
}

解决反射问题

package creatorPattren.singleton.demo05;

/**
 *     第三种饿汉式   实现单例模式
 *    使用内部类的方式实现
 * 使用静态成员变量的方式创建类
 * 向外提供一个公开的获得类的方法
 */
public class Singleton05 {
    private static boolean flag = false;
    //私有化类的构造方法
    private Singleton05() {
        synchronized (Singleton05.class){
            //        解决反射下的破坏单例模式的代码
            if (flag) {
                throw new RuntimeException("不能创建多个对象");
            }
            flag = true;
        }

    }

    private static class getSingleton{
        private static final Singleton05 INSTANCE= new Singleton05();
    }

    public static Singleton05 getIntance() {
        return getSingleton.INSTANCE;
    }
}

你可能感兴趣的:(设计模式,单例模式,原型模式,java)