zoukankan      html  css  js  c++  java
  • 设计模式-单例

    上周开发的时候需要做一个校验用户姓名格式的类,因为提供的是公共功能,类似于工具类,所以最好拿来就能用。内部逻辑大体如下所示:

    public class NameValidateUtil {
        
        // 校验姓名格式是否满足要求
        public boolean validateName (String name) {
            // 判断是不是汉字的姓名
            if (isChineseName(name)) {
                // 是汉字,就用汉字的校验逻辑
                return validateChineseName(name);
            } else {
                // 否则是英文,用英文的校验逻辑
                return validateEnglishName(name);
            }
        }
        
        private boolean validateEnglishName(String name) {
            // 此处省略校验逻辑
            return true;
        }
    
        private boolean validateChineseName(String name) {
            // 此处省略校验逻辑
            return true;
        }
    
        private boolean isChineseName(String name) {
            // 此处省略判断逻辑
            return false;
        }
    }  

    可以看到,校验逻辑比较多,不适合放在一个方法里,如果给每一个方法都加上static也可以做到拿来即用,但这样的设计不够优雅。既然不适合直接用静态的方式,那么很容易就会想到可以用单例模式来实现。其实说实话,在这之前虽然博主也将23中设计模式了解过一遍,但是大多未在项目中实际操作过,所以对设计模式使用的必然性缺少认识,而这一次便让我切身体会到了适合单例模式的使用场景。如上所述的,如果一个类提供的是公共的功能,且不方便给其方法设置成static静态的,那么就可以使用单例模式来实现

    对于单例模式,园友们应该都知道老生常谈的那两种:饿汉式和懒汉式。基本的实现方式大家都清楚,此处就不贴了。饿汉式虽然不会出现线程安全的情况,但除非某些特殊场景,一般都不使用。而一般的懒汉式,对于线程安全的解决办法是双重检查锁(dubbo-check),如下所示:

    public class NameValidateUtil {
        // 私有化构造器,让外部无法对该类实例化
        private NameValidateUtil(){}
    
        private static NameValidateUtil nameValidateUtil;
        
        public static NameValidateUtil getSingleton(){
            if (nameValidateUtil == null) {
                synchronized (NameValidateUtil.class) {
                    if (nameValidateUtil == null) {
                        nameValidateUtil = new NameValidateUtil();
                    }
                }
            }
            return nameValidateUtil;
        }
    }

    但由于JVM的内存模型中允许指令重排序,即在

     nameValidateUtil = new NameValidateUtil();

    这句的三步(a.分配内存地址;b.初始化;c.将内存地址传给引用)中,b与c可能会c先执行,b后执行,这样在高并发的情况下,就可能会出现某个线程获取到了未完成初始化的对象的情况。为避免此情况,可以通过给nameValidateUtil加volatile关键字的方式来避免重排序。

    或者使用静态内部类的方式(静态内部类是在使用的时候才会初始化,且JVM能保证只初始化一次),代码如下所示:

    public class NameValidateUtil {
        // 私有化构造器,让外部无法对该类实例化
        private NameValidateUtil(){}
    
        private static NameValidateUtil nameValidateUtil;
    
        public static NameValidateUtil getSingleton(){
            return InnerNameValidateUtil.innerValidate;
        }
        
        private static class InnerNameValidateUtil {
            static NameValidateUtil innerValidate = new NameValidateUtil();
        }
    }
    

    九月份加班成魔,学习进度严重落后,十月份应该就回归正轨了,务必抓紧时间学习!  

  • 相关阅读:
    转载 centos7安装kafka_2.11-1.0.0 新手入门(集群)
    Kafka得介绍与单节点部署
    MVC Areas
    Session如何保存在sql数据库中
    AsposeCell特定格式表格
    DataTable数据修改,换列
    A1095 Cars on Campus (30 分)
    A1075 PAT Judge (25 分)
    A1016 Phone Bills (25 分)
    A1082 Read Number in Chinese (25 分)
  • 原文地址:https://www.cnblogs.com/zzq6032010/p/11605332.html
Copyright © 2011-2022 走看看