【问题标题】:How to avoid duplication on similar classes and similar methods?如何避免类似类和类似方法的重复?
【发布时间】:2021-07-08 11:03:46
【问题描述】:

上下文

我正在使用非常相似的课程,例如 RechargeResponseConsultResponse。所有这些(大约 80 个)都是从 WSDL 方案生成的,具有相同的结构。 (这个方案来自3PP公司,这个逻辑我改不了。)

每个都包含内部类:RechargeResultConsultResult

我有一堆具有相同功能的方法。唯一的区别是我需要致电(例如)response.get_ClassName_Result().getAny() 来检查数据。

问题

如何避免在每个方法中使用相同的代码而只更改了 ClassNameMethod?


是否可以使用泛型、反射或其他解决方案? (我认为像字符串一样解析类名不是解决方案)。

以下代码示例:

类似的类:

    public class ConsultResponse {
        protected ConsultResult consultResult;
    
        public ConsultResult getConsultResult() {
            return consultResult;
        }
    
        public static class ConsultResult {
            protected Object any;
            public Object getAny() {
                return any;
            }
            public void setAny(Object value) {
                this.any = value;
            }
    
        }
    }

   public class RechargeResponse {
        protected RechargeResult rechargeResult;
    
        public RechargeResult getRechargeResult() {
            return rechargeResult;
        }
    
        public static class RechargeResult {
            protected Object any;
            public Object getAny() {
                return any;
            }
            public void setAny(Object value) {
                this.any = value;
            }
    
        }
    }

每个类的相似(重复)方法:

    private void validateConsult(ConsultResponse response) {
        if (response == null ||
        response.getConsultResult() == null ||              // need solution here
        response.getConsultResult().getAny() == null) {     // need solution or change here
        throw new Exception();
        }
    }

 

【问题讨论】:

  • 我不明白的是:你的两个内部类都是静态的......那么首先拥有两个不同的内部类有什么意义呢?是什么阻止了具有基本实现的外部独立基类?如果您的内部类实际上做了不同的事情,那么您的示例应该表明这一点。
  • 这不是我的解决方案。这些类来自外部 API,由 WSDL 方案生成。我需要实现我的逻辑来提取数据。所以我正在尝试为 validateConsult 方法找到一个解决方案,以便不创建一堆类似的方法。
  • 那我不明白你的问题。代码生成了,又不能改,怎么帮忙???
  • 抱歉造成混淆,我需要通过 ClassName 的模式来提取调用类似方法的数据。您对解决方案的评论很好,但这会吸引第三方更改许多课程(大约 80 个)。之后,如果他们决定进行小的更改,我所有的工作都将被删除。所以这就是为什么我需要找到解决方案——通过ClassName的模式来提取调用类似方法的数据。希望现在更清楚了。

标签: java code-duplication


【解决方案1】:

其中一个问题是您的get«classname»Result 方法名称包含类名称。这使得不使用反射就不可能使其通用。为什么不将两者都重命名为getResult?然后,您可以使用泛型使类成为泛型。

  1. 首先,我们定义一个接口,它同时定义了getAnysetAny

    public interface Result {
        Object getAny();
        void setAny(Object value);
    }
    
  2. 然后我们可以创建Result 的实现,例如ConsultResult。你可以对RechargeResult做同样的事情。

    public class ConsultResult implements Result {
        protected Object any; // You already have a getter, so this can also be private
    
        public Object getAny() {
            return this.any;
        }
    
        public void setAny(Object value) {
            this.any = value;
        }
    }
    
  3. 然后我们可以创建一个基类Response,它定义了getResult 方法。该类接受一个类型参数T,它必须实现Result

    public abstract class Response<T extends Result> {
    
        protected T result; // You already have a getter, so this can also be private
    
        public T getResult() {
            return this.result;
        }
    }
    
  4. 最后,我们还创建了ConsultResponse 类。我们从Response 扩展它,并提供ConsultResult 作为类型参数。

    public class ConsultResponse extends Response<ConsultResult> {
        // The field 'result' is already present within the Response class,
        // so there is no need to include it here.
    }
    

另外,正如 GhostCat 在 cmets 中所说:首先拥有两个不同的内部类有什么意义?在您的示例中,它们与当前编写的示例相同。您可以将它们替换为单个基类;但是,可能是这些类中有更多成员未在您的示例中显示,因此我将它们保留在示例中。


对于验证,您可以做大致相同的操作。

【讨论】:

  • 这是一个很好的解决方案,但我需要重构许多来自外部 API 的类(大约 80 个)。所以,我无法改变他们的逻辑。
  • @Edward 如果你不能改变他们的逻辑,那么你可以做的一件事是使用反射,因为方法名包含类名(我认为这是一个糟糕的设计)。您可以做的另一件事是联系 API 开发人员并要求他们更改 API。
【解决方案2】:

有几种方法可以绕过它,例如创建一个超类,ConsultResponseRechargeResponse 将从该超类扩展。超类将定义共享方法,因此您不必在扩展类中定义它,除非您想覆盖它。

另一种方法是将验证完全分离到一个单独的类中,例如 ResponseValidator,它将自行处理验证,并将包含在 ConsultResponseRechargeResponse 类中并使用。

很难确定一个确切的解决方案,因为这取决于您的具体情况,我们并不完全了解。

【讨论】:

  • 感谢您的回答。我无法更改来自外部 API 的类的逻辑,可能是修改第三方代码以外的其他解决方案。
  • @Edward 您直到现在才提到它是第 3 方代码。抱歉,我不会再花时间在这上面了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多