【问题标题】:Best practice for grouping Java classes for instantiation clarity对 Java 类进行分组以使实例化清晰的最佳实践
【发布时间】:2015-01-03 15:45:54
【问题描述】:

我正在构建一个软件,它以特定二进制定义和特定版本发送和接收消息。因此,我有看起来像这样的类,它们的变化主要在于包名称(在这种情况下是版本):

对于 1.5 版:

com.mydomain.clothesmessage.v0105.fielddefinitions.Field100
com.mydomain.clothesmessage.v0105.fielddefinitions.Field200
com.mydomain.clothesmessage.v0105.messagedefinitions.Pants
com.mydomain.clothesmessage.v0105.messagedefinitions.Socks

对于 2.7 版:

com.mydomain.clothesmessage.v0207.fielddefinitions.Field100
com.mydomain.clothesmessage.v0207.fielddefinitions.Field200
com.mydomain.clothesmessage.v0207.messagedefinitions.Pants
com.mydomain.clothesmessage.v0207.messagedefinitions.Socks

管理这些消息的传输和接收的类使用所有版本,具体取决于消息的来源等。

我的问题是定义类的实例需要我使用整个包路径,否则它会模棱两可。即使存在我在给定文件中仅使用一个版本的情况,代码的普通读者也无法看到正在使用的版本。 Pants pants = new Pants() 在您查看导入的包之前是模棱两可的。

我的理想用法是这样的:

V0207.Pants pantsMessage = new V0702.Pants();

这很清楚正在使用哪个版本。我可以通过将 Pants 消息类创建为 V0207 类的内部类来实现这一点,但随后 V0207 类变得巨大(每个给定版本可能有一百条消息,每条消息有 100 个字段)。有没有办法#include一个内部类,所以它们可以存储在单独的文件中?这将是理想的。

我想我可以用一个包装器类来模拟它,它会做这样的事情(傻吗?),在 V0207 对象中存在 Pants 类的一个实例:

Object pantsMessage = V0207.pants.getClass().newInstance();
((com.mydomain.clothesmessage.v0207.messagedefinitions.Pants)pantsMessage).getZipperType();

但我不喜欢那样。它看起来很做作,在使用时需要尝试/捕获和强制转换。太可怕了。

我也可以使用工厂。这会更好一些,但需要一个父类(或接口),并且在使用时需要强制转换,因为每条消息都有唯一的方法。

Message pantsMessage = V0207Factory.newMessage(V0207.PantsMessage);
((com.mydomain.clothesmessage.v0207.messagedefinitions.Pants)pantsMessage).getZipperType();

Message sockMessage = V0207Factory.newSock();
((com.mydomain.clothesmessage.v0207.messagedefinitions.Socks)sockMessage).getSmellLevel();

你的想法是什么?我正在使用 JDK 1.7,但 1.8 可能可用。

【问题讨论】:

  • 将版本号放在类的构造函数 Javadoc 中。这样,当您将鼠标悬停在构造函数上时,注释将显示版本号。如果您需要每个方法的版本号,您可以创建一个预编译过程,将版本号放在每个方法 Javadoc 上。
  • 是的,构造函数和类的 Javadoc 肯定会包含版本。但这确实需要 IDE 和启动 Javadoc 的操作。此外,这仅解决了问题的一小部分。我真的不想在实例化对象时指定整个包路径。

标签: java inner-classes organization


【解决方案1】:

考虑使用带有接口的工厂设计模式。您使用的 Java 版本并没有什么不同(尽管如果我没记错的话,对 Java 7 的支持会在春季四月停止)。

为每个类定义一个接口,其中包含将由该类的所有版本实现的方法签名。

更新您的类定义以包含适当的接口定义。

为每个需要的类创建一个类工厂,将创建适当版本的类所需的信息传递给它。这个类工厂应该返回创建的类的接口类型。

这是一个例子:

测试裤

public class TestPants {
    IPants pants = PantsFactory.PantsFactory(207);
    Message zipperType = pants.getZipperType();
    Message color = pants.getColor();
    )
}

IPants

public interface IPants {
    Message getZipperType();
    Message getColor();
}

裤子

public class Pants implements IPants {
    // Class fields and Object fields
    @Override
    public Message getColor () {
        return null;
    }
    @Override
    public Message getZipperType () {
        return null;
    }
    // implement any common methods among all versions
}

PantsV0105

public class PantsV0105 extends Pants {
    // add changes for this version
}

PantsV0207

public class PantsV0207 extends Pants {
    // add changes for this version
}

裤子工厂

public class PantsFactory {
    public static IPants PantsFactory(int version) {
        switch (version) {
        case 105: return new PantsV0105(); break;
        case 207: return new PantsV0207(); break;
            default: return null;
    }
}

【讨论】:

  • 啊,是的,我知道我忘记了一些东西。我不想使用工厂,因为它需要一个父类。我会更新我的问题。
  • 结合类工厂使用接口
  • 编辑后:我不知道您使用Interface 是什么意思。我认为消息级别的界面不会很有用。它只会指定版本,对吗?无论如何,版本都可以通过包路径派生。只要我们使用 IDE 来参考文档,Interface 或“just-read-the-package-path”就差不多了。还是我错过了什么?你能举个例子吗?
  • 接口和工厂是你需要的模式。你能提供一些你想用于你的示例类的方法吗?然后我可以提供一个小的工作示例。
  • 方法可以是任何东西,我只需要一个参考。比如说,Pants.showMap() 和 Pants.getDescription()。
【解决方案2】:

我最初通过在一个巨大的“版本”类中使用内部静态类来解决这个问题。因此,使用看起来像这样:

V0207.Pants pantsMessage = new V0702.Pants();

但版本类 ('V0207') 增长太快,特别是团队中的其他开发人员需要一种更“Java”的方式来设置字段(这需要大量的 getter 和 setter)。

因此,最终的解决方案是将消息放在自己的 v0207.messages 包名中,并在每条消息前加上版本:

V0207_Pants pantsMessage = new V0702_Pants();

它不如使用 C++ 命名空间好,但它确实有效。版本对读者来说一目了然,并且对象可以包含大量代码而不会导致任何文件变得太大。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 2013-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多