设计模式(二)---单例模式

吐槽

今天操作系统上课第一天,自己就腰间盘吐出了,被老师记住了,尴尬啊啊啊啊,以后周末还是把这周学的操作系统好好总结下,不然就完了啊啊啊。

参考资料《Android源码设计模式》

什么是单例模式

确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例
这个可能是我之前写项目时候唯一用到的设计模式,写2048游戏的时候就用过这个,不过当时没想这么多。

应用场景

  • 确保某个类有且只有一个对象的场景,避免浪费资源
  • 某种类型的对象只有一个,者避免多个实例由于多次调用
  • 一般访问IO或者数据库等资源的时候考虑

设计思想

因为不允许其他程序new对象然后还有提供一个可以让其他程序获取该对象的方法
所以

  • 构造函数不对外开放,一般为Private
  • 通过一个静态方法或者枚举返回单列类的对象
  • 确保单列的对象有且只有一个,尤其是在多线程的环境中
  • 确保单列对象在反序列化的时候不会重新构造对象

写法

饿汉模式

优点:类加载的时候就完成实例化,避免线程同步问题
缺点:由于在类加载的时候就进行了实例化,所以没有达到Lazy Loading(懒加载)
的效果,即使我们没用到这个实例,但是他还是会加载,从而造成内存浪费(可以忽略,
最常用的一种)

 public class Student(){
        //对象私有,静态
        private static  Student student = new Student();
        //构造方法私有
        private Student(){

        }
        //公有的静态函数,让外面获取这个对象
        public static  Student getStudent(){
            return student;
        }
    }

从上面的代码我们可以看出来:

  • Student类不能以new的形式构造出来,只能通过Student student = Student.getStudent();获取
  • 上面的Student对象是静态的,并在声明的时候已经初始化了,确保了Student对象的唯一性
  • Student类通过一个静态方法,返回一个静态对象

懒汉模式(线程安全,不建议)

懒汉模式是声明一个静态对象,并在用户的第一次调用静态方法时候进行初始化
优点:单例在实用的时候才会初始化,节约了资源
缺点:第一次加载的时候需要及时的实例化,反应慢,而且每次在调用getStudent都进行同步

 public class Student(){
        private static Student student;

        private Student(){

        }
        public static synchronized Student getStudent(){
            if(student == null){
                student = new Student();
            }
            return student;
        }
    }

证了线程安全,但是每个线程在想要获得实例时,执行getInstance()
方法都需要进行同步,而实例化代码只需执行一次就够了,后面获取该实例,
直接return即可,方法进行同步效率太低

懒汉模式双重校验锁(DCL)

DCL模式实现单例模式的优点是既能够在需要的时候才初始化单列,又能保证线程的安全,且单列对象初始化后调用getStudent()不进行同步锁

public class Student {
    private static Student student = null;
    private Student() { }
    public static Student getStudent() {
        if(Student == null) {
            synchronized(Student.class) {
                if(Student == null) {
                    student = new Student();
                }
            }
        }
        return student;
    }
}
1

代码中进行了两次if检查,这样就可以保证线程安全,初始化一次后,
后面再次访问时,if检查,直接return 实例化对象。

静态内部类单例模式(推荐)

虽然DCL模式下的一定程度解决了资源销毁,多余的同步,线程安全等问题,但是还存在失效的问题。
所以选择静态内部类解决这个问题

public class Student(){
        private Student(){

        }
        public static Student getStudent(){
            return StudentnHolder.student1;
        }

        private static class StudentnHolder{
            private static final Student studnet1= new Student();
        }

    }

当第一次加载的时候Student类的时候并不会初始化student1这个对象,只有在第一次调用Student的getStuedents才会让student1被初始化。
这样就满足了线程安全和保证了单例对象的唯一性

枚举单列(推荐)

public enum StudentEnum {
    INSTANCE;
    private Student student;
    StudentEnum() { 
        student = new Student()
    }
    public Student getStudent() {
        return student;
    }
}

访问方式:StudentEnum.INSTANCE.getStudent;
INSTANCE即为SingletonEnum类型的引用,得到它就可以调用
枚举中的方法。既避免了线程安全问题,还能防止反序列化
重新创建新的对象,但是失去了类的一些特性,没有延时加载,

使用容器实现单例模式

public class SingletonManager {
    private static Map<String,Object> objMap = new HashMap<String,Object>();
    private Singleton() { }
    public static void registerService(String key,Object instance) {
        if(!objMap.containsKey(key)) {
            objMap.put(key,instance);
        }
    }
    public static Object getService(String key) {
        return objMap.get(key);
    }
}

将多种单例类型注入到一个统一的管理类中,在使用时根据key获取对象对应类型的对象
这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度

总结

感觉看了这么多,自己写项目时候设计类的话也要好好看下,不管是那种的单例模式,都是将构造方法私有化,然后通过静态的方法获取唯一的单列,但要保证线程安全各种事情。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值