分组 Java 类 以实现实例化清晰度的最佳实践

Best practice for grouping Java classes for instantiation clarity

我正在构建一个软件,可以发送和接收特定二进制定义和特定版本的消息。因此,我有 class 看起来像这样的,它们主要仅在包名称(在本例中为版本)上有所不同:

对于 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

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

我的问题是定义 class 的实例需要我使用整个包路径,否则它会不明确。即使存在我在给定文件中只使用一个版本的情况,随意 reader 代码也无法看到正在使用的版本。 Pants pants = new Pants() 在您查看导入包之前是不明确的。

我的理想用法是这样的:

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

这使得使用的版本一目了然。我可以通过将裤子消息 classes 创建为 V0207 class 的内部 classes 来实现这一点,但随后 V0207 class 变得巨大(可能有一百个消息,每个版本有 100 个字段)。有没有办法 #include 一个内部 class,这样它们就可以存储在单独的文件中?这将是理想的。

我想我可以用一个包装器 class 来模拟它,它做一些事情(愚蠢的?)像这样,在 V0207 对象中存在一个裤子 class 的实例:

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

但我不喜欢那样。它看起来做作并且在使用时需要 try/catch 和转换。太可怕了。

我也可以使用工厂。那会好一点,但需要父 class(或接口)并且在使用时需要强制转换,因为每条消息都有独特的方法。

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 可能可用。

考虑使用带接口的工厂设计模式。您使用的 Java 版本没有区别(尽管如果我没记错的话,对 Java 7 的支持在 spring 的四月份消失了)。

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

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

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

这是一个例子:

试裤

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
}

裤子V0105

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

裤子V0207

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

PantsFactory

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;
    }
}

我最初通过在一个巨大的 "version" class 中使用内部静态 classes 解决了这个问题。因此,使用看起来像这样:

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

但是版本 class ('V0207') 增长太快,尤其是当团队中的其他开发人员需要更多 "Java" 设置字段的方式时(这需要大量吸气剂和吸气剂)。

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

V0207_Pants pantsMessage = new V0702_Pants();

它不如使用 C++ 名称空间好,但它可以工作。版本清晰到reader,对象可以包含很多代码而不会导致任何文件变得太大。