Java 除了使用空的抽象类,还有什么好的替代方法?

Java 除了使用空的抽象类,还有什么好的替代方法?,java,abstract,Java,Abstract,假设我有以下几点: 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 Ab

假设我有以下几点:

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
ResponseB
除了作为一个JSON POJO之外没有任何共同之处。如您所见,我正在使用一个空的抽象类
AbstractResponse
,以避免客户机类
responseClient
responseClient
中的
readResponse()
的代码重复

我的问题

在类似的情况下使用空的抽象类是一种不好的做法吗?如果是,那么最好的编码方式是什么?我曾考虑过使用泛型,但我看到了许多不鼓励使用Java泛型的警告

编辑:感谢大家的快速响应。在@Kayaman的有用评论之后,我想将我的问题重新表述如下:


与使用空接口/抽象类相比,对于我上面描述的这种情况,是否有更好的实现。使用空接口/抽象类似乎是一种不好的做法。

使用接口。使用一个空的抽象类是没有意义的(除非您想阻止这些类子类化另一个类)

至于你的“许多不鼓励使用Java泛型的警告”,我很乐意看到一些链接,因为那不是真的

编辑:通用方法可以提供如下内容(
Response
是一个空接口,用于标记具体的响应类并限制
Client
可以处理的允许类型)

公共类客户端{
私人课堂;
公共客户端(clazz类){
this.clazz=clazz;
}
公共T readResponse(){
ObjectMapper mapper=新的ObjectMapper();
返回(T)mapper.readValue(数据,clazz);
}
}
允许您处理强类型的响应

Client<ResponseA> clientA = new Client<>(ResponseA.class);
ResponseA resp = clientA.readResponse();
clientA=新客户端(ResponseA.class);
ResponseA resp=clientA.readResponse();

因此,“什么是空抽象类的好替代方案”这个问题的答案是“重构和重新设计”。

与其使用空接口或抽象类,不如使用带有
@Retention(RetentionPolicy.RUNTIME)
的注释。不过,这需要编写更多的代码,并且可能不是特别可读和快速的(您希望检查类是否具有此注释的部分)

该语言中有空接口,如
Serializable
。但是由于Java5,它不再有太多意义了

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

我甚至在开始提问之前就知道答案是什么:-)谢谢你的快速回答。为什么使用空接口比使用空抽象类更好?@Diyarbakir这是一个非常基本的问题,我建议你自己查一下(接口和抽象类有什么区别)。@Kayaman抱歉,让我这样重新表述:对于我上面描述的那种情况,是否有比使用空接口/抽象类更好的实现。使用空接口/抽象类似乎是一种不好的做法。@Kayaman感谢您给出了这个明确的答案。这对我有很大帮助。我确实会“重构和重新设计”:)标记接口仍然有意义。我更喜欢方法
void dooFoobar(MarkerInterface对象)
,其中
MarkerInterface
是一个空接口,而不是
void dooFoobar(对象o)
其中o必须被注释。第一个选项在编译时为您提供了更高的类型安全性。虽然空接口并不是最好的方式,但它们仍然有一些用途(特别是如果替代方法是空的抽象类)。正如Alex在他的评论和我在回答中所做的那样,它可以是提供额外类型安全性或限制内容(如参数或泛型)的好方法。@Alex我不确定类型安全性是否适用于这里。知道这个对象实现了一个空接口并没有比知道它扩展了
对象
更大的帮助。如果你需要访问它的成员,你仍然需要一些铸造或反射。但是我同意它更容易编写。使用类型安全性,我的意思是您可以做到:
MarkerInterface mi=getMI();杜福巴-当然,您只负责在必要/正常时实施
标记接口
。但是使用这种方法,您不能执行
dooFoobar(新字符串(“doesnt compile”),如果我使用注释,在编译时就可以了。不要误解我的意思,我并不是说注释在这里是完全错误的,我只是认为标记接口在这里会稍微好一点。
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;
    }
}