简体   繁体   中英

How to avoid duplication on similar classes and similar methods?

Context

I am working with very similar classes like RechargeResponse or ConsultResponse . All of them (around 80) are generated from WSDL scheme has the same structure. (This scheme comes from 3PP company, so I can't change this logic.)

Each of them contains inner classes: RechargeResult and ConsultResult .

I have a bunch of methods with same functionality. The only difference is that I need to call (for example) response.get_ClassName_Result().getAny() to check data.

Question

How can I escape from using in every method same code with only ClassNameMethod changed?


Is any solution like Generics, Reflections or some else could be used? (I think parsing classname like string is not a solution).

Code examples below:

Similar classes:

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

Similar (duplicated) method for each class:

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

One of the problems is that your get«classname»Result method names include the class names. That makes it impossible to make it generic without using reflection. Why don't you just rename both to getResult ? You could then use generics to make the class generic.

  1. First, we define an interface which defines both getAny and setAny .

     public interface Result { Object getAny(); void setAny(Object value); }
  2. Then we could create an implementation of Result , which is, for example, ConsultResult . You could do the same with 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. Then we could create a base class Response , which defines the getResult method. The class accepts a type argument T which must implement 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. At last, we also create our ConsultResponse class. We extend it from Response , and we provide as type argument 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. }

Also, as GhostCat already said in the comments: what is the point of having two different inner classes in the first place? They're both the same in your example as it is currently written. You could replace them with a single base class; however, it could be that there's more members within those classes which are not shown in your example, so I left them as they were in my example.


For the validation you could do roughly the same.

There are several ways around it, for example by creating a superclass from which ConsultResponse and RechargeResponse would be extending. The superclass would have the shared method defined, so you don't have to define it in the extended classes, unless you'd want to override it.

Another approach would be to separate the validation completely into a separate class, for example a ResponseValidator which would handle the validation on its own and would be included and used in the ConsultResponse and RechargeResponse classes.

It's hard to pinpoint an exact solution to this because it depends on your specific situation which we are not aware of completely.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM