设计模式二 单例模式

0、基本定义

  单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点.

通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法,让类自身负责保存它的唯一实例。

这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

要求:

1、构造私有方法

2、定义一个实例,自己实例化

3、获取实例

须 解决一个并发访问的线程安全问题。

 

spring 中默认bean加载都是单例。

1、实现方式

1.1、饿汉式

不管用不用,先new一个对象

public class Emperor {

    private static final Emperor emperor = new Emperor();
    private Emperor() {

    }

    public static Emperor getInstance() {
        return emperor;
    }

    public void say() {
        System.out.println("I am Empror..A. " + this);
    }
}

  

1.2、懒汉式 

默认加载的时候不实例化,在需要用的时候,才加载


public class Singleton {

private static Singleton singleton = null;

private Singleton() {}

/**
* 加 Synchronized, 解决 thread safe
* 性能 差!!!
* @return
*/
public static synchronized LazyTwo getLazy() {
if (lazy == null) {
lazy = new LazyTwo();
}
return lazy;
}

}

 

1.3 内部类

/**
 *  内部类
 * @author zzf
 * @date 2018/8/25 00:14.
 */
public class LazyThree {

    private static boolean initial = false;
    //默认使用LazyThree 的时候,会先初始化内部类
    //如果没有使用的话,内部类是不会加载的
    private LazyThree() {
        //
        synchronized (LazyThree.class) {
            if (initial) {
                initial = !initial;
            } else {
                throw new RuntimeException("单利侵入初始化");
            }
        }
    }

    private static final LazyThree getInstance() {
        return LazyHolder.LAZY_THREE;
    }

    private static class LazyHolder {
        private static final LazyThree LAZY_THREE = new LazyThree();
    }
}

1.4 注册登记式 

 每使用一次,都注册到容器中,下次去对象时,直接从缓存中取值,以保证每次获取的都是 同一个对象。

Spring IOC

/**
 * 注册式
 * @author zzf
 * @date 2018/8/25 00:25.
 */
public class RegisterMap {

    private static Map<String, Object> register = new HashMap();

    public static RegisterMap getInstance(String name) {

        if (name == null) {
            name = RegisterMap.class.getName();
        }

        if (register.get(name) == null) {
            try {
                register.put(name, RegisterMap.class.newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return (RegisterMap) register.get(name);
    }
}

1.5 枚举

注册登记式的一种

public enum RegisterEnum {

    INSTANCE;

    public static RegisterEnum getInstance() {
        return INSTANCE;
    }
}

1.6 序列化和反序列化

序列化与反序列化的时候出现多例: 重写 readResolve()

public class Seriable implements Serializable{

    public final static Seriable instance = new Seriable();

    private Seriable() {}

    public static Seriable getInstance() {
        return instance;
    }

    /**
     * jvm 实现 
     * @return
     */
    private Object readResolve() {
        return instance;
    }

}

test:

public class SeriableTest {

    public static void main(String[] args) {

        Seriable s1 = null;
        Seriable s2 = Seriable.getInstance();

        FileOutputStream fos = null;

        try {
            fos = new FileOutputStream("seriable.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(s2);

            oos.close();
            fos.close();

            ObjectInputStream ois = new ObjectInputStream(
                    new FileInputStream("seriable.obj")
            );
            s1 = (Seriable) ois.readObject();

            System.out.println(s1 == s2);
}
catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }

 

2、优缺点

2.1 、优点:

》减少了内存开支,

》减少了系统的性能开销,当一个对象需要较多资源时,则可以启动时直接产生。 spring IOC

 

2.2、缺点

》 单例模式一般没有接口,扩展困难

》单例模式对测试不利。在并行环境中,如果单例没有完成,是不能进行测试的,没有接口也不能mock的方式虚拟一个对象。??why

》与单一职责有冲突。

2.3 使用场景

》项目中需要一个共享数据或共享访问点,如web页面中计数器

》 创建一个对象需要消耗的资源过多,如 访问IO和数据库等资源

》工具类

 

参考资料:

咕泡学院

《设计模式之蝉》

《大话设计模式》

posted @ 2018-08-24 23:31  小烽  阅读(172)  评论(0编辑  收藏  举报