Как спроектировать объект, который может быть одного из двух типов? - PullRequest
1 голос
/ 27 апреля 2009

Я читаю 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 ]

8 голосов
/ 27 апреля 2009

Не спрашивайте у ваших объектов информацию, а затем принимайте решения относительно того, что они вам говорят. Заставь свои объекты делать работу за тебя. То есть не делайте этого:

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

Это головная боль от обслуживания. Вместо этого сделайте что-то подобное (реализации BodyWrapper будут созданы с использованием метода абстрактной фабрики или аналогичного)

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 не возвращает различные типы внутренних структур, потому что он (возможно, абстрактный базовый класс) делает всю работу за вас.

3 голосов
/ 27 апреля 2009

Для чего же BodyWrapper? Разве parseBody не должен просто вернуть десериализованный объект? Это может быть объект модели или просто пакет значений (словарь / карта / хеш-таблица).

Итак, parseBody нужно проверить тип POST и затем десериализовать. Какие данные вы ожидаете? Результатом должен быть тип, представляющий фактические данные , которые вы хотите, чтобы клиент отправлял в виде java, независимо от как было опубликовано (jason / xml)

3 голосов
/ 27 апреля 2009

Прежде всего, HttpUtils - это способ генерирования имени. Я бы пошел на HttpRequestParser или что-то. Вам также понадобится фабрика, которая будет создавать соответствующую реализацию на основе содержимого типа запроса (XmlRequestParser или JsonRequestParser).

Что касается анализа, я бы порекомендовал проанализировать как XML, так и JSON для некоторого произвольного внутреннего представления (IR), чтобы ваш код выше стека не интересовался такими деталями. IR может быть документом XML или графом объектов.

2 голосов
/ 27 апреля 2009

Просто, чтобы дать вам больше пищи для размышлений, вариант шаблона посетителя, в котором типы данных не связаны между собой временным интервалом , может помочь вам здесь.

Если честно, в данном конкретном случае это также может оказаться излишним, в зависимости от ваших реальных вариантов использования.

Вот некоторый псевдокод:

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

Шаблон Visitor, как правило, полезен, если у вас есть определенный и относительно статический набор «типов данных», которые вы хотите обрабатывать несколькими различными способами.

2 голосов
/ 27 апреля 2009

Узлы JSONObject и DOM не связаны друг с другом в отношении наследования. Это означает, что для перегрузки типа возвращаемого значения он должен будет вернуть object. Это неприятный запах кода, так как вам, вероятно, придется использовать самоанализ, чтобы выяснить, что было возвращено. Как правило, в этой ситуации вы должны использовать виртуальный метод на объекте (теле), который способен правильно воздействовать на тело в зависимости от того, что это на самом деле.

1 голос
/ 27 апреля 2009

Абстракция кажется сложной на этом уровне. Что вы делаете с JSONObject или DOM, возвращаемым как тело? Зачастую легче пойти еще дальше. Возможно ли преобразовать оба в одну и ту же структуру Java? В зависимости от типа содержимого создайте реализацию JSOn или DOM вашего анализатора тела и используйте полученную структуру Java, созданную анализатором, в коде, работающем над телом. При необходимости (для создания правильного формата ответа) вы можете сделать исходный тип содержимого доступным из ответа (getMimeType () или что-то в этом роде).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...