前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式之简单的单例模式如何实现

设计模式之简单的单例模式如何实现

作者头像
海拥
发布2021-08-23 15:28:22
4630
发布2021-08-23 15:28:22
举报
文章被收录于专栏:全栈技术

单例模式的特点:在同一时期,某个类的对象一定最多只有1个!也许会尝试多次的获取对象,但是,获取到的一定是同一个对象!

假设项目中有King类:

代码语言:javascript
复制
public class King {
}

很显然,目前它并不是单例的,因为,可以:

代码语言:javascript
复制
King k1 = new King();
King k2 = new King();
King k3 = new King();

以上代码就创建了3个King类型的对象!如果要实现单例,首先,就必须限制构造方法的访问,例如:

代码语言:javascript
复制
public class King {
    private King() {
    }
}

每个类中都可以有若干个构造方法,如果某个类没有显式的声明任何构造方法,编译器就会自动添加1个公有的、无参数的构造方法!如果类中已经声明任何构造方法,则编译器不会自动添加构造方法!

由于将构造方法声明为私有的,则原有的King k1 = new King();这类代码就不能用于创建对象了!

限制构造方法的访问,其目的是“不允许随意创建对象”,并不是“不允许创建对象”,在King类的内部,还是可以创建对象的,可以添加方法,返回内部创建的对象:

代码语言:javascript
复制
public class King {
    private King king = new King();
    
    private King() {
    }
    
    public King getInstance() {
        return king;
    }
}

所以,当需要King类型的对象时,可以通过getInstance()方法来获取!

但是,以上代码是不可行的!因为,如果要调用getInstance()方法,必须先获取King的对象,而获取King对象的唯一方式就是调用getInstance()方法!为了解决这个问题,必须在getInstance()方法的声明之前添加static修饰符,最终,就可以通过类名.方法名()的语法格式来调用方法了!同时,由于“被static修饰的成员,不可以访问其它未被static修饰的成员”,所以,全局属性king也必须被static修饰:

代码语言:javascript
复制
public class King {
    private static King king = new King();
    
    private King() {
    }
    
    public static King getInstance() {
        return king;
    }
}

至此,基本的单例模式的代码就设计完成了!

以上代码是“饿汉式”的单例模式,另外,还有“懒汉式”的单例模式!

基本的懒汉式单例模式的代码是:

代码语言:javascript
复制
public class King {
    private static King king = null;
    
    private King() {
    }
    
    public static King getInstance() {
        if (king == null) {
            king = new King();
        }
        return king;
    }
}

注意:以上代码是多线程不安全的!

在开发领域中,只要数据的产生、变化不是开发人员预期的,就称之为“不安全”,也就是“数据安全问题”。

为了保障线程安全,应该为以上创建对象的代码片断“加锁”,例如:

代码语言:javascript
复制
public class King {
    private static King king = null;
    
    private King() {
    }
    
    public static King getInstance() {
        synchronized ("hello") {
            if (king == null) {
                king = new King();
            }
        }
        return king;
    }
}

当然,无论是哪个线程在什么时候执行以上代码,都必须先“锁住”代码片断后才能开始执行,是没有必要的,“锁”的性能消耗是浪费的,所以,可以进一步调整为:

代码语言:javascript
复制
public class King {
    private static King king = null;
    
    private King() {
    }
    
    public static King getInstance() {
        if (king == null) { // 判断有没有必要锁定接下来的代码
            synchronized ("java") {
                if (king == null) { // 判断有没有必要创建对象
                    king = new King();
                }
            }
        }
        return king;
    }
}

至此,懒汉式的单例模式就完成了!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/07/06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档