如何在一系列对象中传递Java引用的最佳方法

5

让我们考虑这样一串对象:

Earth->Continent->Country->City->name

让我们考虑 Earth.class 具有 public static void main(String[] args) 的情况。

当应用程序使用命令行选项例如 Barcelona 执行时,最好的方法是如何将其传递给 City 对象而不引入中间参数?

对象在程序执行的不同阶段创建。

我们应该使 name 变量静态还是使用诸如 Spring 或 Google Guice 的 IoC?是否有其他选项?

欢迎任何想法。

3个回答

2
  • 我认为在这个任务中最好使用IOC。让IOC在构建城市时传递依赖。
  • 另一种方法:使用静态服务注册表,可以查询值。城市可以从服务注册表获取其名称。
  • 另一种方法:在您的层次结构上实现组合模式,包括一个名为find的函数,它可以返回城市。然后您只需要查询和设置earth.find(BarcelonaID).setName(args[0]);

PicoContainer中IoC解决方案的示例:

PicoContainer container = new DefaultPicoContainer();
container.addComponent(Earth.class);
container.addComponent(Continent.class);
container.addComponent(Country.class);
container.addComponent(City.class, new ConstantParameter(cityName));

City barcelona = container.getComponent(City.class);

谢谢,克里斯托弗。IoC看起来不错,但最初需要基础设施来支持,比如Spring和Guice。我想知道是否有必要建立这样的设置,只是为了将几个命令行参数传递到正确的位置 :) - Ivan Balashov
@IvanBalashov 基础设施很简单。请参考示例。 - Christopher Oezbek

2

你可以从自上而下的方式构建数据结构 -- 大陆构建城市,或者从自下而上的方式 -- main 构建城市并将其传递给国家,或者使用一些组合。依赖注入更倾向于后者。

public static void main(String... argv) {
  // Bottom up.
  City city = new City(/* args relevant to city */);
  Country country = new Country(city, /* args relevant to country */);
  Continent continent = new Continent(country, /* args relevant to continent */);
  Planet planet = new Planet(continent, /* args relevant to planet */);
}

class City {
  City(/* few parameters */) { /* little work */ }
}
class Country {
  Country(/* few parameters */) { /* little work */ }
}
...
class Planet {
  Planet(/* few parameters */) { /* little work */ }
}

相比自上而下的方式,这种方法可以更加简洁:

public static void main(String... argv) {
  // Top down.
  Planet earth = new Planet(
    /* all the parameters needed by Earth and its dependencies. */);
}
class Planet {
  Planet(/* many parameters */) { /* lots of work */ }
}
...

DI 的支持者认为自底向上的构建方式可以产生更易于维护和测试的代码,但你并不需要 DI 框架来使用它。

谢谢,迈克。幸运的是,对象需要在地球类之外构建。否则,这将不会有趣 :) - Ivan Balashov
@IvanBalashov,我主张在外部构建它们。 - Mike Samuel
@MikeSamuel 我认为在它们应该存在的地方之外创建对象不是一个好主意。一个国家需要知道哪些城市属于它,如果你把这个知识放在 Country 类之外,那么你就违反了对象封装。 - GETah
@MikeSamuel 我明白了,通过这样做,你仍然暴露了只有“国家”应该知道的细节,不是吗? - GETah
@GET啊,暴露只有国家应该知道的细节给谁? - Mike Samuel
显示剩余2条评论

1
在我看来,这是访问者模式最好的使用案例。 基本上,应该有一个类参数来保存所有参数。需要一组参数的每个对象都可以使用该参数类进行访问。然后,对象可以将参数传递给其知道要使用哪些参数以及如何使用的子级。 在您的情况下,可以这样做:
public interface IParameterized{
   public void processParameters(Parameters param);
}

public class Earth implements IParameterized{
   public Earth(){
      // Create all countries here and store them in a list or hashmap 
   }
   public void processParameters(Parameters param){
      // find the country you want and pass the parameters to it
      country.processParameters(param);
   }
} 

public class Country implements IParameterized{
   public Country(){
      // Create all cities that belong to this country
   }
   public void processParameters(Parameters param){
      // find the city you want and pass the parameters to it
      city.processParameters(param);
   }
} 

public class City implements IParameterized{
   public City(){
      // Create city...
   }
   public void processParameters(Parameters param){
      // Do something with the parameter
   }
}

编辑 要连接这些点,可以按以下方式使用:

public static void main(String... argv) {
     Parameters params = new Parameters();
     // Populate params from the command line parameters
     Earth earth = new Earth();

     // Earth takes the responsibilty of processing the parameters
     // It will delegate the processing to the underlying objects in a chain
     earth.processParameters(params);
}

另外,您也可以查看责任链设计模式。


谢谢,GETah。但我们仍然需要在某个地方保存IParameterized对象,并将其传递给其他对象,这意味着所有引用都应该在一个地方可用。我想知道是否能找到真正解耦的东西 :) - Ivan Balashov
@IvanBalashov 参数将在主函数中创建并向下传递,请查看我的编辑。 - GETah
是的,但是你必须在 main() 函数内部有 EarthCity 和其他对象可用,这些对象在我的情况下是在其他地方创建的... - Ivan Balashov
@IvanBalashov 只有在 main() 函数内部会创建 Earth 对象,其他对象将在不同的地方创建:Countries 可以在任何地方创建,但必须从 Earth 引用,依此类推。 - GETah
@IvanBalashov 请查看我的编辑。我已经添加了构造函数到代码中,以便让您知道应该在哪里创建不同的对象。 - GETah

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