OO vs. Layered; балансировка "ОО чистота" с получением вещи - PullRequest
4 голосов
/ 30 сентября 2008

Я верю в ОО, но не до такой степени, что несоответствующие проекты / реализации должны использоваться просто для того, чтобы быть "ОО-совместимыми".

Итак, как работать с многоуровневой архитектурой Serlvet / EJB / DataContainer:

  • Сервлеты получают запросы и вызывают «бизнес-уровень» (например, сессионные EJB)
  • Бизнес-уровень находит DataContainer из базы данных и манипулирует ими для реализации бизнес-логики
  • DataContainers не содержат реального кода, просто получите / установите соответствующий базе данных.

Этот подход имеет привлекательность; DataContainers четко знают, что они делают, и очень легко узнать, откуда поступают данные.

Помимо того, что это не OO, это приводит к неясным классам бизнес-уровня, которые сложно назвать и которые сложно организовать.

Даже если бы мы пытались быть более «ОО» (например, помещая некоторые из этих методов в DataConatiners), некоторые из этих операций работают с более чем одним набором данных.

Как вы удерживаете свой бизнес-уровень от запутывающей процедурной, но не загрязняете ваши DataContainers бизнес-логикой?

* * Пример 1 022
class UserServlet {
  handleRequest() {
    String id = request.get("id");
    String name = request.get("name");
    if (UserBizLayer.updateUserName(id,name))
      response.setStatus(OK);
    else
      response.setStatus(BAD_REQUEST);
  }
}

class UseBizLayer {
    updateUserName(String id, String name) {
        long key = toLong(id);
        user = userDAO.find(key);
        if user == null
            return false;
        if (!validateUserName(name))
            return false;
        user.setName(name);
        userDAO.update(user);
        return true;
    }

    validateUserName(String name) {
        // do some validations and return
    }
}

class User {
    long key;
    String name;
    String email;

    // imagine getters/setters here
}
  • Мы не хотим validateUserName для пользователя, поскольку он работает только с именем; Я думаю, это может перейти в другой класс, но тогда у нас есть другой класс процедурного типа "uti"
  • Нам не нужны методы персистентности для пользователя, поскольку есть смысл в отделении структур данных от их стратегии персистентности
  • Нам не нужна бизнес-логика в нашем сервлете, поскольку нам может потребоваться повторно использовать эту логику в другом месте
  • Нам не нужна наша бизнес-логика для нашего пользователя, поскольку она слишком сильно притягивает класс пользователя, затрудняя повторное использование бизнес-логики и связывая пользователя с его стратегией постоянства

Я понимаю, что этот пример не так уж плох, но представьте 10 объектов DataContainers и 20 объектов BizLayer с несколькими методами каждый. Представьте, что некоторые из этих операций не «центрированы» на конкретном контейнере данных.

Как мы можем предотвратить это как процедурный беспорядок?

Ответы [ 6 ]

3 голосов
/ 30 сентября 2008

Итак, я расскажу об этом в нескольких пунктах:

  1. Кажется, что в системе Java EE в какой-то момент вам приходится иметь дело с сантехникой Java EE, сантехника не всегда извлекает выгоду из концепций ОО, но она, безусловно, может потребовать немного творчества и работы. Например, вы можете воспользоваться такими вещами, как AbstractFactory и т. Д., Чтобы помочь объединить как можно большую часть этой инфраструктуры.
  2. Многое из того, что вы изучаете, обсуждается в превосходной книге Эрика Эванса «Доменное управление». Я настоятельно рекомендую вам взглянуть на него, поскольку он решает проблему выражения знаний в этой области и имеет дело с технической инфраструктурой для ее поддержки.
  3. Прочитав и применив некоторые из DDD, я бы инкапсулировал свою техническую инфраструктуру в репозитории. Все репозитории будут написаны так, чтобы использовать стратегию постоянства, основанную на ваших сессиях EJB. Вы бы написали реализацию по умолчанию, которая знает, как общаться с вашей сессионной EJBS. Чтобы это работало, вам нужно добавить немного соглашения и указать это соглашение / контракт в ваших интерфейсах. Хранилища делают все CRUD и должны делать больше, чем это, если это абсолютно необходимо. Если бы вы сказали «Мои DAOS - мои репозитории», я бы согласился.
  4. Итак, чтобы продолжить это. Вам нужно что-то для инкапсуляции единицы работы, которая выражается в UseBizLayer. На этом уровне, я думаю, суть в том, что вы застряли при написании кода, который все будет представлять собой сценарий транзакции. Вы создаете разделение ответственности и государства. Как правило, именно так я и делал в системах Java EE в качестве архитектуры по умолчанию. Но это не объектно-ориентированный. Я попытался бы изучить модель и посмотреть, смогу ли я хотя бы попытаться обобщить некоторые из поведений, записанных в BizClasses.
  5. Другой подход, который я использовал ранее, состоит в том, чтобы избавиться от классов BizLayer и затем передать вызовы из Домена фактическим репозиториям / DAO, выполняющим эту операцию. Однако это может потребовать некоторых инвестиций в создание инфраструктуры. Но вы могли бы многое сделать с такой средой, как Spring, и использовать некоторые концепции AOP, чтобы сделать это хорошо и сократить количество необходимой инфраструктуры.
1 голос
/ 30 сентября 2008

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

Простой пример ... Клиент заполняет форму для запроса виджета, передает его сотруднику, сотрудник проверяет личность клиента, обрабатывает форму, получает виджет, передает виджет и запись транзакции клиент и ведет учет транзакции где-то для компании.

Хранит ли клиент свои данные? Нет, работник делает. Какую роль играет сотрудник, когда он хранит данные клиента? Хранитель клиентских записей.

Проверяет ли форма, что она была заполнена правильно? Нет, работник делает. Какую роль играет сотрудник, когда он это делает? Обработчик форм.

Кто дает клиенту виджет? Сотрудник, выступающий в роли распространителя виджетов

И так далее ...

Чтобы вставить это в реализацию Java EE ...

Сервлет действует от имени Клиента, заполняя форму (извлекая данные из HTTP-запроса и создавая соответствующий объект Java), и передает ее соответствующему сотруднику (EJB), который затем обращается с формой, что необходимо быть сделано. При обработке запроса, EJB может потребоваться передать его другому EJB, который специализируется на различных задачах, часть из которых будет включать в себя доступ / размещение информации из / в хранилище (ваш уровень данных). Единственное, что не должно отображаться непосредственно на аналогию, это особенности взаимодействия ваших объектов друг с другом и взаимодействия вашего уровня данных с вашим хранилищем.

1 голос
/ 30 сентября 2008

так как вы реализуете классы и объекты, ваше решение будет ОО независимо от того, как вы раскладываете вещи - оно может быть не очень хорошо структурировано в зависимости от вашей ситуации / потребностей! ; -)

Что касается вашего конкретного вопроса, в некоторых случаях было бы целесообразно, чтобы validateUserName принадлежало классу User, поскольку каждый пользователь хотел бы иметь действительное имя. Или вы можете иметь класс утилиты проверки, предполагая, что другие вещи имеют имена, которые используют те же правила проверки. То же самое касается электронной почты. Вы можете разделить их на классы NameValidator и EmailValidator, что будет хорошим решением, если они будут использоваться часто. Вы также можете предоставить функцию validateUserName для объекта User, который только что вызвал метод класса утилит. Все это действительные решения.

Одна из самых больших радостей в OOD / OOP заключается в том, что когда дизайн правильный, вы знаете , что это правильно, потому что многие вещи просто выпадают из модели, которую вы можете сделать, что вы не мог сделать раньше.

В этом случае я бы создал классы NameValidator и EmailValidator, потому что вполне вероятно, что другие объекты будут иметь имена и адреса электронной почты в будущем, но я бы предоставил функции validateName и validateEmailAddress для класса User, потому что это обеспечивает более удобный интерфейс для бизнес-объектов для использования.

остальные пули «мы не хотим» верны; они необходимы не только для правильного наслоения, но и для чистой ОО-конструкции.

Слои и ОО идут рука об руку, основываясь на разделении проблем между слоями. Я думаю, что у вас есть правильная идея, но вам понадобятся некоторые служебные классы для общих проверок, представленные

0 голосов
/ 15 октября 2009

Я думаю, что это вопрос о «разделении интересов». Вы, кажется, далеко продвинулись по правильному пути со своей многоуровневой архитектурой, но, возможно, вам нужно сделать больше того же самого - то есть создать архитектурные слои в ваших слоях Java EE?

DataContainer очень похож на шаблон объектов передачи данных (DTO).

В современном дизайне ОО есть много маленьких классов, каждый из которых связан с небольшим количеством «друзей», например, с помощью композиции. Это может создать гораздо больше классов и шаблонов Java, чем вам действительно удобно, но это должно привести к созданию более многослойного проекта, который будет легче тестировать и обслуживать.

(+ 1 за вопрос, +1 за ответ о том, когда вы знаете, что у вас есть право на слои)

0 голосов
/ 30 сентября 2008

У меня тоже были такие же мысли.

В традиционном MVC самое важное - это отделить представление от частей модели и контроллера. Кажется, хорошей идеей будет разделить контроллер и модель просто потому, что вы можете получить раздутые объекты модели:


public class UserModel extends DatabaseModel implements XMLable, CRUDdy, Serializable, Fooable, Barloney, Baznatchy, Wibbling, Validating {
  // member fields
  // getters and setters
  // 100 interface methods
}

Принимая во внимание, что вы можете иметь отдельные контроллеры (или целые шаблоны) для многих из вышеперечисленных интерфейсов, и да, это скорее процедурный характер, но я думаю, именно так все и работает в наши дни. В качестве альтернативы вы можете понять, что некоторые интерфейсы выполняют одно и то же (CRUDdy - хранение и извлечение базы данных, Serializable - то же самое в двоичном формате, XMLable, то же самое в XML), поэтому вы должны создать единую систему для обработки этого каждый потенциальный бэкэнд является отдельной реализацией, которую обрабатывает система. Боже, это действительно плохо написано.

Может быть, есть что-то вроде "совместных классов", которые позволяют вам иметь отдельные исходные файлы для реализации контроллера, которые действуют так, как будто они являются членами класса модели, на который они действуют.

Что касается бизнес-правил, то они часто работают над несколькими моделями одновременно, и поэтому они должны быть отдельными.

0 голосов
/ 30 сентября 2008

Грубо, раздел «Мы не хотим» должен уйти. Либо вы хотите, чтобы все было правильно, либо вы хотите, чтобы все оставалось как есть. Нет смысла в , а создавать класс, когда он вам нужен. «У нас много» - плохое оправдание.

Действительно, это плохо, чтобы показывать все внутренние классы, но, по моему опыту, создание класса для концепции (то есть пользователя, идентификатора, концепции базы данных) .) всегда помогает.

Кроме того, не является ли шаблон Facade чем-то, что решает проблему существования множества классов BizRules, скрытых за одним хорошо организованным и чистым интерфейсом?

...