【问题标题】:Java: identical Objects, how to avoid duplicated codeJava:相同的对象,如何避免重复代码
【发布时间】:2015-02-11 16:40:56
【问题描述】:

我有一个使用外部库调用各种网络服务的项目。这个库给了我这样的对象:

public static class ObjA {
    @XmlElement(name = "counter", required = true)
    protected BigInteger counter;
    @XmlElement(name = "data", required = true)
    protected String data;
    [...]
}

还有这个:

public static class ObjB {
    @XmlElement(name = "counter", required = true)
    protected BigInteger counter;
    @XmlElement(name = "data", required = true)
    protected String data;
    [...]
}

如您所见,objA 和 objB 具有相同的属性,因此,如果我必须同时使用两者,我必须复制代码:

public class myClass {

    [...]
    private ObjA a;
    private ObjB b;
    [...]

    public void myClass() {
        [...]
        this.a = new ObjectFactory().createObjA();
        this.b = new ObjectFactory().createObjB();
        [...]
    }

    public void init() {
        this.initA();
        this.initB();
    }

    private void initA() {
        this.a.setCounter(BigInteger.ZERO);
        this.a.setData = "";
    }

    private void initB() {
        this.b.setCounter(BigInteger.ZERO);
        this.b.setData = "";
    }

    [...]
}

initA 和 initB 相同,无法访问库代码,无法创建通用接口,如何避免重复代码?我的意思是,有可能有这样的东西吗?

    private void initObj([ObjA|ObjB] obj) {
        obj.setCounter(BigInteger.ZERO);
        obj.setData = "";
    }

谢谢!穆夏斯·格拉西亚斯!

附录

请注意,我无法访问底层库,因此我无法以任何方式添加修改类、接口、wsdl 或 xsd。 同样在我看来,是否使用 ws、jaxb 或其他库并不重要:您可以想象没有注释的 ObjA 和 ObjB,如下所示:

public static class ObjA {
    protected BigInteger counter;
    protected String data;
    [...]
}

public static class ObjB {
    protected BigInteger counter;
    protected String data;
    [...]
}

问题的症结没有改变。

【问题讨论】:

  • 如果你不能创建一个通用接口(在这个例子中是抽象类),你必须编写代码来初始化类型ObjA和类型ObjB不管你做什么。跨度>
  • 您可以使用动态方法(反射或 BeanUtil)以相同的方法处理不同的类型。然而,这有许多自己的问题(静态分析不知道),所以我通常会远离它。我们对上下文一无所知,因此可能还有其他解决方案。并且不要忘记与 API 提供者交谈。
  • 我会创建一个超级类,手动编辑生成的(猜想每个类只有一个地方),然后阅读我和一段视频,说明做了什么以及为什么做了。
  • @tgkprog 我无法“手动编辑生成的”,我无权访问源代码。无论如何,我认为如果由于某种原因必须重新生成代码,则强制重新编辑代码真的很糟糕。

标签: java oop code-duplication


【解决方案1】:

我假设这些类是使用某种工具为您生成的,也许是 maven cxf-codegen-plugin 等。 如果是这种情况,您需要修改 WSDL 和 XSD,以便生成令您满意的 DTO 类。 如果向您提供了 WSDL,那么您只需按原样接受服务?

如果您知道常用方法都具有相同的名称,您可以使用反射吗?

所以你会用原始反射做这样的事情:

import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

public class Test {    
    public static void initObject(Object o) throws Exception {
        if (!(o instanceof ObjA)&&!(o instanceof ObjB)) return;
        Method m = o.getClass().getMethod("setCounter",java.math.BigInteger.class);
        m.invoke(o,BigInteger.ZERO);
        m = o.getClass().getMethod("setData",java.lang.String.class);
        m.invoke(o,"");
    }

    public static void main(final String[] args) throws Exception {
        List<Object>objects = new ArrayList<Object>();
        //this is like your factory method
        Object o = Class.forName("ObjA").newInstance();
        initObject(o);
        objects.add(o);
        o = Class.forName("ObjB").newInstance();
        initObject(o);
        objects.add(o);
    }
}

如果你想使用一个库,你可以使用 JXPath 和 see docs here 之类的东西 但我认为出于您的目的,原始反射可能很好。不需要庞大复杂的反射库。

【讨论】:

  • 我无法修改 WSDL 或 XSD。我正在考虑反思,但正如@L.Butz 所说,这是一种不好的做法。
  • 这通常是不好的做法,仅仅是因为很难正确地做到这一点。但是反射实际上几乎用于您选择的每个主要 Java 库,特别是 Jackson 等。我想不出任何不涉及某种基于反射的解决方案的方法来解决您的问题。您可以尝试使用 xpath 之类的方法为您进行反思commons.apache.org/proper/commons-jxpath
  • 我认为你是对的。您会发布一个解决 ObjA 和 ObjB 问题的示例的答案,以便我最终接受它吗?
  • 我在上面添加了一个例子
  • 你可以缓存方法,只做一次,以后只调用
【解决方案2】:

我想您正在使用 JAXB。您可以阅读对象列表。 看到这个帖子:JAXB Unmarshalling: List of objects

【讨论】:

  • 这将如何避免 OP 的 myClass 中的代码重复?请解释!
  • 这不是对象列表,它们是两个相同的对象,但定义了两个名称,就像拥有 my lillte book 12my good film 24:bookdata 和 filmdata 相同,但不同的对象
  • 为了提供更好的帮助,您应该提供有关该问题的更多信息,例如:您是否使用 JAXB?您将调用 1 个网络服务,并通过该回复构建对象 A 和 B?或者他们会从不同的ws源获取信息?
  • 重点是我没有访问库,也没有访问 WSDL、XSD 等...无论如何,我认为对象是否通过 ws 或不是,它们只是两个相同的对象,底层是一个接受它们的黑盒子。
【解决方案3】:

由于它们没有通用接口(或父类?),我想要走的路是使用 java 反射。

自己创建一些反射辅助方法,如“init(Class clazz)”并调用构造函数。

请记住,在大多数情况下,java 反射是不好的做法,因此请确保没有其他/更好的方法来实现您的目标。

【讨论】:

  • 技术上可行,但当我试图想象“辅助方法”的签名和生成的代码时,我不禁颤抖起来。并且编译时错误检查将延迟到运行时。
猜你喜欢
  • 2023-03-22
  • 2019-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-29
  • 1970-01-01
相关资源
最近更新 更多