简体   繁体   中英

What is a good alternative to using an empty abstract class?

Suppose I have the following:

public abstract class AbstractResponse {
  // this class is totally empty!
}

public class ResponseA extends AbstractResponse {
  // JSON POJO 
}

public class ResponseB extends AbstractResponse {
  // JSON POJO 
}

public abstract class AbstractClient {
  public abstract Class getType();

  public AbstractResponse readResponse() {
    ObjectMapper mapper = new ObjectMapper();
    AbstractResponse response;
    try {
        return (AbstractResponse) mapper.readValue(data, getType());
    } catch (IOException e) {...}
  }
}

public class ResponseAClient extends AbstractClient {
  public Class getType() {
    return ResponseA.class;
  }
}

public class ResponseBClient extends AbstractClient {
  public Class getType() {
    return ResponseB.class;
  }
}

ResponseA and ResponseB have nothing in common besides being a JSON POJO. As you can see I am using an empty abstract class AbstractResponse to avoid duplicated code for readResponse() in the client classes ResponseAClient and ResponseBClient .

My question :

Is it bad practice to use an empty abstract class for similar cases and if so, what would be the best way to code this? I have thought about using generics but I've seen many warnings that discourage the use of Java Generics.

Edit: Thanks for the quick response guys. After the useful comments from @Kayaman I'd like to rephrase my question like this:

Is there a better implementation for the kind of situation I've described above than using an empty interface/abstract class. It just seems like bad practice to have an empty interface/abstract class.

Use an interface. There's no sense in using an empty abstract class (unless you want to prevent the classes from subclassing another class).

As for your "many warnings that discourage the use of Java Generics.", I'd be happy to see some links, because that's just not true.

Edit: A generic approach could give you something like the following ( Response is an empty interface for marking concrete response classes and limiting the allowed types that Client can handle)

public class Client<T extends Response> {
    private Class<T> clazz;
    public Client(Class<T> clazz) {
        this.clazz = clazz;
    }
    public T readResponse() {
        ObjectMapper mapper = new ObjectMapper();

        return (T) mapper.readValue(data, clazz);
    }
}

Allowing you to handle responses that are strongly typed.

Client<ResponseA> clientA = new Client<>(ResponseA.class);
ResponseA resp = clientA.readResponse();

So the answer to the question "What's a good alternative to an empty abstract class" is "Refactor and Redesign".

Instead of using an empty interface or abstract class, I'd rather use an annotation with @Retention(RetentionPolicy.RUNTIME) . That is a little more code to write though, and may not be especially readable and fast (the part where you want to check if a class has this annotation).

There are empty interfaces in the language, like Serializable . But since Java 5 it doesn't make too much sense anymore.

import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public abstract class AbstractClient {
    public abstract Class getType();

    public Object readResponse() {
        ObjectMapper mapper = new ObjectMapper();
        try {
            Object response = mapper.readValue(data, getType());

            if (response.getClass().getDeclaredAnnotation(Response.class) == null) {
                // Not a valid type
            }

            return response;
        } catch (IOException e) {...}
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Response {

}

@Response
class ResponseA extends AbstractResponse {
    // JSON POJO
}

@Response
class ResponseB extends AbstractResponse {
    // JSON POJO
}


class ResponseAClient extends AbstractClient {
    public Class getType() {
        return ResponseA.class;
    }
}

class ResponseBClient extends AbstractClient {
    public Class getType() {
        return ResponseB.class;
    }
}

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