Android开发Android开发经验谈Android技术知识

Java设计模式 | 单例模式解析与实战

2020-04-10  本文已影响0人  凌川江雪

定义

确保某一个类只有一个实例
而且自行实例化并向整个系统提供这个实例

使用场景

确保某个类有且只有一个对象的场景,
避免产生多个对象消耗过多的资源,
或者
某种类型的对象只应该有且只有一个。
例如,
创建一个对象需要消耗的资源过多,
如要访问IO和数据库等资源,这时就要考虑使用单例模式。

单例模式UML类图

(1)Client——高层客户端;
(2)Singleton——单例类。

重点,注意单例模式中 volatile的重要性

单例的几种实现方式

1. 饿汉模式

声明一个静态类对象,在声明时就己经初始化
用户调用类对象get方法时,可以直接拿去用;
【一声明就初始化,所谓“饿”】

如下,
CEO类使用了饿汉单例模式;

/**
 * 普通员工
 */
class Staff {
    public void work() {
        // 干活
    }
}
// 副总裁
class VP extends Staff {
    @Override
    public void work() {
        // 管理下面的经理
    }
}
// CEO, 饿汉单例模式
class CEO extends Staff {
    private static final CEO mCeo = new CEO();

    // 构造函数私有
    private CEO() {
    }

    // 公有的静态函数,对外暴露获取单例对象的接口
    public static CEO getCeo() {
        return mCeo;
    }
    @Override
    public void work() {
        // 管理VP
    }

}
// 公司类
class Company {
    private List<Staff> allPersons = new ArrayList<Staff>();

    public void addStaff(Staff per) {
        allPersons.add(per);
    }

    public void showAllStaffs() {
        for (Staff per : allPersons) {
            System.out.println("Obj : " + per.toString());
        }
    }
}
public class Test {
    public static void main(String[] args) {
        Company cp = new Company();
        // CEO对象只能通过getCeo函数获取
        Staff ceo1 = CEO.getCeo();
        Staff ceo2 = CEO.getCeo();
        cp.addStaff(ceo1);
        cp.addStaff(ceo2);
        // 通过new创建VP对象
        Staff vp1 = new VP();
        Staff vp2 = new VP();
        // 通过new创建Staff对象
        Staff staff1 = new Staff();
        Staff staff2 = new Staff();
        Staff staff3 = new Staff();

        cp.addStaff(vp1);
        cp.addStaff(vp2);
        cp.addStaff(staff1);
        cp.addStaff(staff2);
        cp.addStaff(staff3);

        cp.showAllStaffs();
    }
}

2. 懒汉模式

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

这种模式一般不建议使用!!!!!!!!!!

3. DoubleCheckLock(DCL)实现单例【双重校验锁】

public class Singleton {
        private volatile static Singleton sInstance = null;
        private Singleton() {
        }
        public void doSomething() {
            System.out.println("do sth.");
        }
        public static Singleton getInstance() {
            if (mInstance == null) {
                synchronized (Singleton.class) {
                    if (mInstance == null) {
                        sInstance = new Singleton();
                    }
                }
            }
            return sInstance;
        }

4. 静态内部类单例模式

public class Singleton {
        private Singleton() { }
        public static Singleton getInstance () {
            return SingletonHolder.sInstance;
        }
        /**
         * 静态内部类
         */
        private static class SingletonHolder {
            private static final Singleton sInstance = new Singleton();
        }
    }

5. 枚举单例

除了以上几种方式,还有更简单的实现方式——枚举!:

public enum SingletonEnum {
        INSTANCE;
        public void doSomething() {
            System.out.println("do sth.");
        }
    }
private Object readResolve() throws ObjectStreamException {
    return sInstance;
}

即在readResolve()中将sInstance对象返回,
而不是默认的重新生成一个新的对象。
而对于枚举,并不存在这个问题,
因为即使反序列化它也不会重新生成新的实例。







参考:

上一篇 下一篇

猜你喜欢

热点阅读