• 小晏子
    2020-02-07
    课堂讨论,
    1. 把代码“User cachedUser = CacheManager.getInstance().getUser(userId);”单独提取出来做成一个单独的函数,这样这个函数就可以进行mock了,进而方便测试validateCachedUser。
    2. 可以判断传进来的参数和已经存在的instance里面的两个成员变量的值,如果全部相等,就直接返回已经存在的instance,否则就新创建一个instance返回。示例如下:

    public synchronized static Singleton getInstance(int paramA, int paramB) {
        if (instance == null) {
            instance = new Singleton(paramA, paramB);
        } else if (instance.paramA == paramA && instance.paramB == paramB) {
            return instance;
        } else {
            instance = new Singleton(paramA, paramB);
        }
        return instance;
    }
    展开
     7
     12
  • webmin
    2020-02-07
    1. 如果项目中已经用了很多单例模式,比如下面这段代码,我们该如何在尽量减少代码改动的情况下,通过重构代码来提高代码的可测试性呢?
    CacheManager.getInstance(long userId)中增加Mock开关,如:
    private User mockUser;
    public CacheManager.setMockObj(User mockUser)
    public User getInstance(long userId) {
         if(mockUser != null && mockUser.getUserId() == userId) {
              return mockUser
         }
    }
    2. 在单例支持参数传递的第二种解决方案中,如果我们两次执行 getInstance(paramA, paramB) 方法,第二次传递进去的参数是不生效的,而构建的过程也没有给与提示,这样就会误导用户。这个问题如何解决呢?
    第一次构造Instance成功时需要记录paramA和paramB,在以后的调用需要匹配paramA与paramB构造成功Instance时的参数是否一至,不一至时需要抛出异常。
    展开
     1
     4
  • 黄林晴
    2020-02-07
    打卡
    
     4
  • Jeff.Smile
    2020-02-07
    模式没有对错,关键看你怎么用。这句话说的很对,所以其实所谓单例模式的缺点这种说法还是有点牵强!
    
     3
  • Eden Ma
    2020-02-07

    2、instance不为空抛出异常
    
     2
  • bin
    2020-02-10
    第一个问题:把 CacheManager.getInstance().getUser() 封装成一个函数,可以用来mock
    public User getCacheUser(long userId){
    }

    第二个问题,加一个判断,

    public synchronized static Singleton getInstance(int paramA, int paramB) {
     if (instance == null) {
         instance = new Singleton(paramA, paramB);
         return instance;
     }
    if( instance != null && (paramA != this.paramA || paramB != this.paramB ) ){
         throw new RunTimeException("不能重复初始化");
    }
     return instance;
    }
    展开
    
    
  • 天天向上卡索
    2020-02-10
    在 .net core 里,依赖注入模式的使用比较多,对于一些配置会通过options模式来处理,option也可以注入,很灵活
    
    
  • Uncle.Wang
    2020-02-09
    我遇到的问题是:在client端开发的时候,工程中有大量单例,这些单例中保存着数据,而这些数据可能是和用户账户相关联的,一旦切换账号,面临reset这些单例的问题,往往存在遗漏。如果大量存在这种单例,会很难维护。
    
    
  • Ken张云忠
    2020-02-09
    1.下面这段代码,我们该如何在尽量减少代码改动的情况下,通过重构代码来提高代码的可测试性呢?
    将单例类中新增一个用于获取测试instance的函数,命名getTestInstance(User testUser),该函数中把需要的测试用例通过参数传入instance当中,当要做测试时就可以通过getTestInstance函数来获取实例得到需要的测试数据.
    public boolean validateCachedUser(long userId) {
        User actualUser = userRepo.getUser(userId);
        //User cachedUser = CacheManager.getInstance().getUser(userId);//生产使用
        User cachedUser = CacheManager.getTestInstance(actualUser).getUser(userId);//测试使用
        // 省略核心逻辑:对比cachedUser和actualUser...
      }
    2.第二次传递进去的参数是不生效的,而构建的过程也没有给与提示,这样就会误导用户。这个问题如何解决呢?
    第二次调用getInstance时如果带有与之前相同参数就直接返回instance实例;如果参数不相同且业务允许构建新的instance实例就允许再第二次getInstance时构建新的实例,如果业务不允许就在构建时抛出异常.
    public synchronized static Singleton getInstance(int paramA, int paramB) {
        if (instance == null) {
          instance = new Singleton(paramA, paramB);
        } else if (this.paramA != paramA || this.paramB != paramB) {
           //instance = new Singleton(paramA, paramB);// 业务允许
           throw new RuntimeException("Singleton has been created!");// 业务不允许
       }
        return instance;
      }
    展开
    
    
  • 守拙
    2020-02-09




    课堂讨论

    1. 修改validateCachedUser()方法形参:

       public boolean validateCachedUser(int userId,     CacheManager manager){...}

    ​

    2. 带有参数的getInstance()的一种实现方式:

       public syncrinized static Singleton getInstance(int paramA, int paramB){

       ​ if(instance == null){

       ​ instance = new Singleton(paramA, paramB);

       ​ }

       

       ​ if(this.paramA != paramA || this.paramB != paramB){

       ​ instance = new Singleton(paramA, paramB);

       ​ }

       

       ​ return instance;

       }
    展开
    
    
  • mghio
    2020-02-09
    优秀,单例模式竟然还有这么多问题以前只是用,从来没有考虑过这方面
    
    
  • test
    2020-02-08
    1.把单例部分抽出来;
    2.为空或者一致的时候返回可用instance,不一致则抛错。
    
    
  • 平风造雨
    2020-02-08
    问题2使用不同参数构造不同单例,是这个需求吗?如果是那么维护类就不能只有一个instance的成员变量,应该考虑有类似cachedMap的方式,instance要实现equals和hashCode方法,针对不同入参作为不同的key,线程安全的去访问cachedMap进行存取。
    
    
  • 失火的夏天
    2020-02-08
    直接更新属性怕是会有一个安全问题吧,一个长线程如果一直在使用对象,一个其他线程进来后,把这个单例对象的属性直接修改了。长线程接下来如果使用到单例对象,属性就全变了。线程安全性太差了。
    
    
  • 忆水寒
    2020-02-07
    第一个问题,为了增加可测试性,也就是尽量可以测试中间结果。我觉得可以将cacheUser那一行代码和下一行代码分别抽取出来封装📦。
    第二个问题,可以将参数保存在静态类中,本身这个类新增一个init函数,在new 对象后进行调用init。这样用户可以不需要加载参数。当然了,如果一定要在getInstance时传入参数,那么也可以校验参数是否和上一次传入的参数是否一致。
    
    
  • 往事随风,顺其自然
    2020-02-07
    第一个问题可以先抽取一个函数,然后mock 第二个问题,可以比较传入的参数对比,相同才进行新建对应对象
    
    
  • 好吃不贵
    2020-02-07
    关于单例模式的替换方案。类实现时normalClass用普通写法,构造函数也是public的。在类外面,全局定义static normalClass obj;这样直接调用obj的方法是不是也是全局唯一了,至少同一进程内是一样的,也算是一种单例的替代方案?
    
    
  • 辣么大
    2020-02-07
    思考题1:
    提出一个方法:public Uer getCahcedUser(userId){},然后mock getCahcedUser方法。
    测试:
    public boolean validateCachedUesr(userid){
      User cachedUser = getMockCachedUser…
      User actualUser = userRepo.getUser(userid)
    // validate …
    }

    思考题2:
    A singleton with parameters is NOT a singleton because you may have more object than one of them.
    改进:得到单例对象后,再初始化参数。
    SingletonObj singleton = SingletonObj.getInstance()
    singleton.init(paramA, paramB)
    展开
     1
    
  • Yang
    2020-02-07
    1.通过参数的方式将单例类传递进函数。
    2.如果单例对象存在,就对比两个成员变量,不一致就抛出异常提示调用方,一致就直接返回单例对象。
    
    
  • 石维康
    2020-02-07

    public class Singleton {
      private static Singleton instance = null;
      private final int paramA;
      private final int paramB;

      private Singleton(int paramA, int paramB) {
        this.paramA = paramA;
        this.paramB = paramB;
      }

      public static Singleton getInstance() {
        if (instance == null) {
           throw new RuntimeException("Run init() first.");
        }
        return instance;
      }

      public synchronized static Singleton init(int paramA, int paramB) {
        if (instance != null){
           throw new RuntimeException("Singleton has been created!");
        }
        instance = new Singleton(paramA, paramB);
        return instance;
      }
    }

    Singleton.init(10, 50); // 先init,再使用
    Singleton singleton = Singleton.getInstance();

    请问老师这里的init方法为何需要返回一个Singleton?写成void不行吗?
    展开
     1
    
我们在线,来聊聊吧