Шаблон программирования / архитектурный вопрос - PullRequest
4 голосов
/ 05 января 2010

В настоящее время я работаю над проектом, в котором у меня есть объект BankAccount для какого-либо другого объекта.

Каждый банковский счет является ссылкой на банковский объект, номер счета и, возможно, IBAN.

Теперь, когда IBAN может быть проверен, как я могу гарантировать, что, когда IBAN установлен для учетной записи, действителен.Каков будет чистый архитектурный подход?В настоящее время у меня есть слой домена без какой-либо ссылки на какой-либо другой уровень, и мне нравится этот чистый подход (меня вдохновил Эрик Эванс DDD).К счастью, проверку IBAN можно выполнить без доступа к какой-либо внешней системе, поэтому в этом случае у меня может быть что-то вроде

puclic class BankAccount
{
  public string Iban
  {
     set { // validation logic here }
  }
}

Но теперь я думал, какой подход я бы использовал, если проверка IBAN требует проверки SQL-сервера дляНапример, или внешняя DLL.Как бы я это реализовал.Буду ли я создавать объект значения IBAN, который передается в службу, которая решает, является ли IBAN действительным или нет, и после этого устанавливает его для объекта BankAccount?Или я бы создал фабрику, которой разрешено создавать экземпляры IBAN и выполнять проверку раньше?

Спасибо за вашу помощь!

Ответы [ 6 ]

5 голосов
/ 05 января 2010

Я бы использовал некоторую форму Инверсии Контроля.

Если быть точным, у меня был бы интерфейс под названием IIBANValidator. Различные средства проверки IBAN должны реализовывать этот интерфейс. Например:

interface IBANValidator {
    Boolean Validate(string iban);
}

class SqlBanValidator : IBANValidator {

    public bool Validate(string iban) {
        // make the sql call to validate..
        throw new NotImplementedException();
    }

}

Тогда в моем классе BankAccount должен был бы быть метод, который бы принимал объект, который реализует IIBANValidator и номер IBAN и был структурирован как (не оптимизированный никакими отрезками):

Boolean SetIBAN(IIBANValidator validator, String iban) {
  Boolean result = false;
  if (validator.Validate(iban)) {
    Iban = iban;
    result = true;
  }

  return result;
}

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

Окончательный код будет выглядеть примерно так:

BankAccount account = new BankAccount();
account.SetIBAN(new SqlBanValidator(), "my iban code");

Очевидно, что во время выполнения вы можете передать любой экземпляр валидатора, какой захотите.

2 голосов
/ 05 января 2010

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

Должен ли BankAccount иметь изменяемый номер IBAN? Я не очень знаком с банковским делом, но это звучит как страшная идея.

1 голос
/ 05 января 2010

Вы можете реализовать Спецификацию , которая использует Внедрение зависимости для Репозитория Но вы теряете немного сплоченности.

Более подробную информацию можно найти здесь .

0 голосов
/ 07 января 2010

Я бы сделал аспектно-ориентированным и уменьшил бы связь.

    [IBANVlidator(Message = "your error message. can also come from culture based resouce file.")]
    public string IBAN
    {
        get
        {
            return _iban;
        }
        set
        {
            this.validate();
            _iban = value;
        }
    }

this.validate () вызывается из базового класса вашего BankAccount , который перебирает все свойства, имеющие атрибут проверки. Атрибуты проверки - это пользовательские атрибуты, полученные из класса ValidationAttribute, которые могут нацеливать свойства класса.

Ответственность за проверку IBAN затем передается атрибуту валидации IBANValidator. Конечно, эта схема может быть улучшена, что выходит за рамки этого ответа.

0 голосов
/ 07 января 2010

Вы можете просто использовать делегат для проверки, вам не нужно передавать весь интерфейс, кто хочет установить его, должен иметь валидатор.

public delegate bool Validation(IBAN iban);
void SetIBAN(IBAN iban, Validation isValid){ 
  if(!isValid(iban)) throw new ArgumentException();
...}
0 голосов
/ 05 января 2010

Где разместить логику проверки, зависит от того, какая информация необходима для выполнения этой проверки. Проверка должна выполняться в типе, который имеет достаточно информации для этого. С другой стороны, необходимо учитывать сложность логики валидации. Например, если у вас есть данные электронной почты, прикрепленные только к типу «Человек», они могут быть проверены «на месте» внутри типа «Человек», поскольку проверка не сложна (при условии, что проверен только формат электронной почты), и «Персона» является единственным потребителем. Если, с другой стороны, у вас есть данные о сделках (характеризуемые данными о товарах и ценах), используемые типами Store и Garage (продажа ваших старых вещей) с логикой проверки, что товары должны принадлежать инициатору сделки, имеет смысл поместить проверку в тип сделки .

...