Как разделить обязанности, когда требования развиваются таким образом? - PullRequest
0 голосов
/ 20 декабря 2011

Сначала мое требование было

«Мы можем создать счет, положив на него деньги, когда мы покупаем товар, мы уменьшаем счет»

Итак, мой AccountController выглядел как

class AccountController
{
    private IAccountDataSource _accountDataSource;

    Create(Account anAccount)
    {
        _accountDataSource.Insert(anAccount);
         Render(anAccount.Id);
     }
}

Но тогда возникает новое требование «У некоторых людей может быть бесплатная учетная запись (все элементы будут бесплатными), но если мы создадим реальную учетную запись, мы удалим бесплатную учетную запись»

Итак, мой контроллер. Создать стал

Create(Account anAccount)
{
    _accountDataSource.Insert(anAccount);
    RemoveFreeAccount(anAccount.Customer);
    Render(anAccount.Id);
}

RemoveFreeAccount(Customer aCustomer)
{
    _accountDataSource.Remove(new AccountFilter() { Type='Free', CustomerId=aCustomer.Id });
}

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

1 Ответ

1 голос
/ 23 марта 2012

Проблема показывает, что вы нарушаете SRP. Ваш контроллер не должен содержать бизнес-логики. Использование репозитория непосредственно в контроллере заставляет вас вкладывать в него всю логику и, следовательно, получать две обязанности (быть мостом между M в MVC + обработка бизнес-логики).

Первая часть рефакторинга должна состоять в том, чтобы переместить бизнес-логику в модель (в MVC ее не следует путать с моделью сущностей или моделью представления)

это дает вашему исходному коду следующую структуру:

public class AccountService
{
    void CreateAccount(string accountName)
    {
       var account = new Account(accountName);
        _dataSource.Create(account);
        DomainEvents.Publish(new AccountCreated(account));
    }
}

public class AccountController
{
    private AccountService _service;

    Create(AccountViewModel model)
    {
        var account = _accountDataSource.Create(model.Name);
        Render(account.Id);
     }
}

Изменение может выглядеть незначительным, но важно:

  1. Контроллер теперь имеет только одну причину для изменения (отображение между видом и моделью)
  2. Любое изменение бизнес-требований не приведет к изменениям уровня пользовательского интерфейса.
  3. Изменения в требованиях вносятся только в одном месте

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

public class FreeAccountService : ISubscriberOf<UserCreated>, ISubscriberOf<AccountCreated>
{
    public FreeAccountService(AccountService)
    {
    }

    public void HandleEvent(UserCreated domainEvent)
    {
        accountService.Create(new FreeAccount());
    }

    public void HandleEvent(AccountCreated domainEvent)
    {
        var freeAccount = dbSource.GetFreeAccount();
        if (freeAccount != null)
            accountService.Delete(freeAccount)
    }
}

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

...