繁体   English   中英

静态初始化块的设计问题

[英]Design issue on static initialization block

我有一个设计问题:让我在简单的例子中解释一下:

Public class A()
{
public static HashMap map = new HashMap();
public static String url = "default";
static {
  getJson();
}

//url getters and setters are defined

public static getJson() {
//code which uses url to get json and populate hashmap
}
public string getresult(String key) {
//uses hashmap to send result.
}

我正在使用静态初始化块,因为我只想一次获取json。

public class B {

//这里我要更改url并调用getJson方法。 如果我调用A.setUrl(),那么在设置url之前,将在静态初始化块中按原样调用A.getJson()方法。我该如何先设置url然后再调用getJson()。

//is this a bad design?

}

我猜这应该工作。 添加新方法。

public static void getJson(String url) {
setUrl(url);
getJSon();
}

静态初始化器通常是一个坏主意,因为单元测试变得困难。

查看Misko Hevery编写可测试代码的指南

您可以通过执行以下操作来重新设计:

public class A {
  //Add generics
  private Map map = new HashMap();
  public A(Map map){
    this.map = map;
  }
  public String getresult(String key) {
  //uses hashmap to send result.
  }

}

//Helper Class
public class URLToJSon() {
//Add private constructor
  public static Map convertUrlToJSon(String url) {
   //do the conversion and return a hashmap
  }
}

通过这种方式,我们可以遵循单一责任原则

现在,这两个类也都可以测试。

是的,这是糟糕的设计:

  1. 在不修改A定义的情况下,无法自定义A从何处获取数据。除其他外,这会阻止单元测试(因为如果网络不可用,您可能不想使单元测试失败...)。
  2. 如果初始化失败(例如,因为远程URL当前不可用),您将不容易捕获该异常,因为您不知道哪个访问触发了加载。 您不能从静态初始值设定项引发检查异常。 您也不能重试初始化(所有后续访问都会立即导致异常)。

如果必须通过静态字段访问A ,我建议:

public class A {
    private static Map<String, String> map;

    /** must be invoked before get is first called */
    public static void init(Map<String, String> newmap) {
        map = newmap;
    }

    public static String get(String key) {
        return map.get(key);
    }
}

这将使用数据的关注与获取数据的关注区分开了,从而允许分别替换和测试每个数据。

还应考虑摆脱static ,因为它强制在整个应用程序中同时只有一个映射,这非常不灵活。 (有关方法,请参见Ajay答案中的第二个代码示例)

URL在哪里设置? 在构造函数中? 如果是这样,只需做

//Normal init stuff like set url here, followed by
if (! some check for if json is set) {
     setJson();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM