首页 > 解决方案 > 当派生类主要用于扩展状态而不是行为时,如何在继承层次结构中动态获取子类?

问题描述

我正在尝试使用 Jumblr 来使用我的 tumblr 数据,Jumblr是 Java 的 Tumblr API 包装器客户端。

我研究了源代码,发现由于 Json 响应是动态的,因此有一个 Post POJO 和派生的 POJO,如 TextPost、QuotePost、PhotoPost 等,可以反序列化为 pojo。它通过将 Gson 与使用反射的自定义反序列化器一起使用以通用方式处理消费。通过这种方式,例如,它将对 TextPost 的 Json 响应反序列化并将其分配给 Post 对象。

因此,为了获得子类的字段,我需要在instanceof这样的检查后向下转换 Post 对象:

List<Post> posts =  blog.draftPosts();
Post post = posts.get(0); //gets a TextPost
if(post instanceof TextPost) {
    System.out.println("title: " + ((TextPost) post).getTitle());
    System.out.println("body: " + ((TextPost) post).getBody()); 
}
else if(post instanceof QuotePost) {
    //...
}
else if...

我不确定这是最好的方法。所以我从多态等面向对象编程概念的角度寻找更优雅或最好的方法或正确的方法。

从超类获取子类或访问它的正确方法是什么?

您如何评估 API 的面向对象设计,它通过扩展包含额外状态的特定类来使用继承?从处理响应的客户的角度来看,这是一种合理的方法吗?还有哪些其他方法?既然不是行为继承,那用继承只继承状态对吗?

从 API 源:


public class Post {
    protected PostType type;
    private Long id;
    private String author;
    private String reblog_key;
    private String blog_name;
    //more state and getters/setters
}

public class TextPost extends Post {
    //extra fields
    private String title;
    private String body;

    //getters/setters
}


public List<Post> getPosts() {
    Gson gson = gsonParser();
    JsonObject object = (JsonObject) response;
    List<Post> l = gson.fromJson(object.get("posts"), new 
                        TypeToken<List<Post>>() {}.getType());
    ...
}

private Gson gsonParser() {
        return new GsonBuilder().
            registerTypeAdapter(Post.class, new PostDeserializer()).
            create();
    }

public class PostDeserializer implements JsonDeserializer<Object> {

    @Override
    public Object deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException {
        JsonObject jobject = je.getAsJsonObject();
        String typeName = jobject.get("type").getAsString();
        String className = typeName.substring(0, 1).toUpperCase() + typeName.substring(1) + "Post";
        try {
            Class<?> clz = Class.forName("com.tumblr.jumblr.types." + className);
            return jdc.deserialize(je, clz);
....

}

标签: javaoopinheritancedesign-patternsinstanceof

解决方案


首先:没有“正确”的方法,而是优雅和不优雅的方法。处理此类问题的常见模式是以下之一:

  1. 让不同的类由对象的子类决定如何处理(就像您在示例中所做的那样)。
  2. 通过抽象基类的(抽象)方法将处理子类状态的责任转移到子类中,每个子类都必须以自己的方式实现。
  3. 将处理子类状态的责任转移到访问者 ( https://en.wikipedia.org/wiki/Visitor_pattern ) 中,每个子类都会“访问”该访问者,并根据调用对象的类型实现行为。

推荐阅读