静态初始化块的设计问题

4

我有一个设计问题:让我用简单的例子来解释:

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()方法。

//我希望先调用A.setUrl()方法设置URL,然后再调用getJson()方法。您可以使用以下代码:

A.setUrl(url);
A.getJson();

//is this a bad design?

}

3
任何可变的静态内容都很可能是非常糟糕的设计。如果你只想在特定上下文中创建一个实例,请在该上下文中仅构造一次即可。 - Tom Hawtin - tackline
顺便问一下,你是否使用原始类型,因为你的目标Java版本早于1.5? - hertzsprung
3个回答

2
这应该可以正常工作,我猜的。添加一个新方法。
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
  }
}

以这种方式,我们遵循了单一职责原则
现在这两个类也可以进行测试。

2

是的,这是糟糕的设计:

  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,因为它强制要求在应用程序中同时只能存在一个 map,这样显得相当不灵活。(参见 Ajay 答案中的第二个代码示例)


1

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接