如何设计一个可以是两种类型之一的对象?

时间:2009-04-27 07:49:28

标签: java oop

我正在阅读HTTP POST,HTTP请求的主体可以是JSON或XML。 现在我已将读数委托给一个特殊的实用程序类。

interface HttpUtils
{
    BodyWrapper parseBody( HttpServletRequest req );
}

interface BodyWrapper
{
    boolean isXML();  // 1
    boolean isJSON(); // 2
    String body();    // 3
}
  • 我讨厌BodyWrapper有方法(1& 2)来识别它的类型。也许我应该使用继承。如果我这样做,我将需要做一个instanceof来找出HttpUtils.parseBody(..)
  • 返回的内容
  • 理想情况下,我还希望body()方法返回JSONObject或DOM节点。我该怎么做?

6 个答案:

答案 0 :(得分:8)

不要向对象询问信息,然后就他们告诉您的内容做出决定。让您的对象为您完成工作。也就是说,不要这样做:

if (body.isXML()) {
  // do XML stuff
}
else if (body.isJSON()) {
  // do JSON stuff
}

这是一个令人头疼的问题。做这样的事情(BodyWrapper实现将使用abstract factory method或类似的)

创建
public interface BodyWrapper {
   Object doStuff();
}

public class DOMBodyWrapper implements BodyWrapper {
   public Object doStuff() {
   }
}

public class JSONBodyWrapper implements BodyWrapper {
   public Object doStuff() {
      // do something and return a success/failure result. I've
      // deliberately not defined what this object is....
   }
}

然后:

// get the body via a factory or similar
body.doStuff();

这样,某些东西会创建适当的BodyWrapper实现,然后不再询问它是什么类型,而是使用它。请注意,BodyWrapper不会返回不同类型的内部结构,因为它(可能是一个抽象基类)正在为您完成工作。

答案 1 :(得分:3)

首先,HttpUtils是通用名称的方式。我会选择HttpRequestParser或其他什么。您还需要一个工厂,它将根据请求的内容类型(XmlRequestParserJsonRequestParser)创建适当的实施。

就解析而言,我建议将XML和JSON解析为一些任意的内部表示(IR),这样堆栈中较高的代码就不会关注这些细节。 IR可以是XML文档,也可以是某个对象图。

答案 2 :(得分:3)

BodyWrapper到底是什么意思? parseBody不应该只返回de-seriealized对象?这可能是一个模型对象,也可能只是一个值包(字典/ map / hashtable)。

因此,parseBody需要检查POST的类型然后反序列化。你期待什么数据?结果应该是一种类型,表示您希望客户端以java方式发布的实际数据,无论 是如何发布的(jason) / xml)

答案 3 :(得分:2)

JSONObject和DOM节点彼此无关,继承明智。这意味着为了在返回类型上重载,它必须返回object。这是一个令人讨厌的代码味道,因为你可能必须使用内省来找出返回的内容。通常在这种情况下,您应该在对象(主体)上使用虚拟方法,该方法能够以正确的方式对身体起作用,具体取决于实际情况。

答案 4 :(得分:2)

只是为了给你一些思考的东西,访问者模式的一种变体,其中数据类型与interitance无关,可以帮助你。

老实说,根据您的实际使用情况,在这种特殊情况下也可能会出现过度杀伤。

这是一些伪代码:

interface BodyTypesVisitor
{
   void visit( DOMNode domNode );
   void visit( JSONObject jsonObject );
}

interface BodyWrapper
{
    void accept( BodyTypesVisitor );
}

interface HttpUtils
{
    BodyWrapper parseBody( HttpServletRequest req );
}

class DOMVisitor implements BodyTypesVisitor
{
   void visit( DOMNode domNode ) { /* do something useful with domNode */ }
   void visit( JSONObject jsonObject ) { /* ignore */ }
}

class DOMBody implements BodyWrapper
{
    ...

    void accept( BodyTypesVisitor visitor )
    { visitor.visit( this->domNode ); }

    private DOMNode domNode;
}

...
// Process DOM
BodyWrapper wrapper = <some HttpUtils implementation that creates a DOMBody>
DOMVisitor visitor = new DOMVisitor();

wrapper.accept(visitor);

如果您想要以多种不同的方式处理一组独特且相对静态的“数据类型”,则访问者模式通常很有用。

答案 5 :(得分:1)

这个级别的抽象似乎很难。你如何处理作为正文返回的JSONObject或DOM?通常更容易更进一步。是否可以将两者转换为相同的Java结构?根据内容类型,创建正文解析器的JSOn或DOM实现,并在正文中使用的代码中使用由解析器创建的结果java结构。如果需要(创建正确的答案格式),您可以从答案中获取原始内容类型(getMimeType()或类似的内容)。