Критерии проектирования на основе домена - PullRequest
1 голос
/ 31 марта 2011

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

Проблемы

Меня беспокоит только то, что это выглядит анемично.

Шаги

  1. Создание нового запроса со значениями
  2. подтвержден ли запрос?
    1. Если да, показать значения
    2. Если нет, показать причины, не утвержденные

Классы

enum UnitedStatesState {
  ALABAMA,
  //...
  CALIFORNIA,
  //...
  MAINE,
  //...
  WASHINGTON
}

class License {
  int id;
  String name;

  //enum of state that the license is applicable in
  UnitedStatesState state; 
}

class LicenseRequest {
  //the name of the person making the request
  String name; 

  //enum of state to which the user is requesting a license in
  UnitedStatesState state; 

  LicenseResponse submit()
  {
     //TODO: move creation of the rules out of this class
     RuleGroup<LicenseRequest> ruleGroup = new RuleGroup<>();
     ruleGroup.add(new StateExclusionLicenseRequestRule(UnitedStatesState.MAINE));

     boolean approved = ruleGroup.execute(this);
     if(approved) {
       License license = createLiscense(request);
       return new ApprovedLicenseResponse(license);
     } else {
       DeniedLicenseResponse response = new DeniedLicenseResponse();
       response.rules = newArrayList(ruleGroup);
       return response;
     }
  }

  //TODO: move create license out of Request. maybe a factory class?
  private License createLicense()
  {
     License license = LicenseIdGenerator.generate(this.state);
     license.name = this.name;
     license.state = this.state;
     save(license);
     return license;
  }
}

//visitor for the rule
interface Rule<T> {
  public boolean execute(T o);
  public List<String> getMessages();
}

//rule that auto denies when the request is made in an excluded state
class StateExclusionLicenseRequestRule : Rule<LicenseRequest> {
  public List<String> getMessages();
  UnitedStatesState excludedState;
  public boolean execute(LicenseRequest request) {
     if(request.state == excludedState)
     {
       messages.add("No license for " + request.state + " is available at this time.");
       return false;
     }
     return true;
  }
}

//rule that groups all other rules
class RuleGroup<T> : Rule<T> {
  public void addRule(Rule<T> rule);
  public List<Rule<T>> getFailedRules();

  public List<String> getMessages() {
     List<String> messages = new ArrayList<>();
     for(Rule<T> rule : rules) {
       messages.addAll(rule.getMessages());
     }
     return messages;
  }

  public boolean execute(T o) {
     List<Rule<T>> failedRules = new ArrayList<>(rules.size());
     for(Rule<T> rule : rules) {
       boolean approve = rule.execute(o);
       if(!approve) {
         failedRules.add(rule);
       }
     }
     return !failedRules.isEmpty();
  }
}

interface LicenseResponse {
  boolean approved;
}

class ApprovedLicenseResponse : LicenseResponse {
  License license;
}
class DeniedLicenseResponse : LicenseResponse {
  private List<Rule<LicenseRequest>> rules;

  public List<String> getMessages()
  {
     List<String> messages = new ArrayList<>();
     for(Rule<LicenseRequest> rule : rules) {
       messages.addAll(rule.getMessages());
     }
     return messages;
  }
}

Пример кода

request = new Request(name: 'Test', state: UnitedStatesState.CALIFORNIA)
response = request.submit()
if(response.approved)
{
  out('Your request is approved');
  out('license id = ' + reponse.id);
}
else
{
  out('Your request was denied');
  for(String message : response.messages)
  {
    out(message);
  }
}

Обновление 1: фон

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

В качестве примера, единственное правило состоит в том, что запрос на получение лицензии в штате Мэн отклоняется.

Обновление 2: Правила рефакторинга и удалениеОбработчик

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

Ответы [ 2 ]

2 голосов
/ 01 апреля 2011

К сожалению, некоторые из наиболее важных кодов не показаны, но я хотел бы посмотреть, какой код можно вставить в LicenseRequest.В частности, LicenseRequest может создать License вместо обработчика (возможно, присвоив ему идентификатор).Это особенно верно, если есть свойства LicenseRequest, которые используются только при создании утвержденной лицензии.Тогда их не нужно показывать с помощью получателей.

Я бы также determineApproval (возможно, с другим именем) создавал ответ напрямую, а не передавал список сообщений для записи (который используется только при сбоях).

Запах, который вы должны искать, Feature Envy .В частности, любые проверки с использованием данных из License или LicenseRequest должны быть проверены, чтобы увидеть, следует ли выполнять эти вычисления вместо этого в этих классах.

Существует цель для объектов данных (в частности, неизменяемых объектов данных),но вы правы, чтобы беспокоиться.

0 голосов
/ 23 июня 2015

Состояния должны быть ValueObjects для расширяемости.Например, что происходит, когда вам нужно приравнять аббревиатуру штата к его названию?

Похоже, что ваш проект на самом деле не имеет совокупных корней.Является ли LicenseRequest бессмысленным без лицензии для обсуждения?В этом случае он должен обрабатываться через лицензию (или службу лицензий), а не напрямую с помощью вызывающего кода (например, веб-сервер, консольное приложение и т. Д.).

Так что для псевдокодакак

var license = licenseFactory.NewLicense();
response = license.Request(name, state)

имеет больше смысла?Что происходит, когда у вас есть несколько типов лицензий, таких как коммерческие драйверы?

Кроме того, для правил, а не для шаблона команды (выполнить), вы могли бы получить более чистое решение, имея Правила в качестве спецификаций - https://en.wikipedia.org/wiki/Specification_pattern

...