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

//is this a bad design?

}
4

3 回答 3

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,因为它会强制您的整个应用程序中同时只有一个地图,这是非常不灵活的。(请参阅 Ajay 答案中的第二个代码示例以了解如何)

于 2012-08-06T20:21:18.037 回答
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
  }
}

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

现在这两个类也都是可测试的。

于 2012-08-06T19:36:28.703 回答
1

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

//Normal init stuff like set url here, followed by
if (! some check for if json is set) {
     setJson();
}
于 2012-08-06T19:27:10.083 回答