interface IMembershipService
{
bool ValidateUser(string username, string password);
MembershipCreateStatus Create(string username, string password);
}
Создание такой службы как анти-шаблон.
Сколько обязанностей у такой службы? Сколько причин может измениться?
Кроме того, если вы поместите свою логику в сервисы, вы получите анемичный домен. В итоге вы получите процедурный код в стиле сценария транзакции. И я не говорю, что это обязательно плохо.
Возможно, модель с богатым доменом вам не подходит, но это должно быть осознанное решение между ними, и эта служба множественной ответственности не подходит ни в одном из случаев.
Это должен быть ОГРОМНЫЙ красный флаг:
public MembershipCreateStatus Create(string username, string password)
{
return membershipRepository.Create(username, password);
}
Какой смысл? Слои ради слоев? Сервис не добавляет здесь никакой ценности, не имеет смысла.
Пропущено множество понятий.
Сначала рассмотрим использование Фабрики для создания объектов:
public interface IMembershipFactory {
MembershipCreateStatus Create(string username, string password);
}
Фабрика может инкапсулировать любую логику, которая используется для создания экземпляра или начала срока службы объекта-сущности.
Во-вторых, Репозитории - это абстракция коллекции объектов. Как только вы использовали фабрику для создания объекта, добавьте его в коллекцию объектов.
var result = _membershipFactory.Create("user", "pw");
if (result.Failed); // do stuff
_membershipRepository.Add(status.NewMembership); // assumes your status includes the newly created object
Наконец, класс MyEntityService
, содержащий метод для каждой операции, которая может быть выполнена над сущностью, кажется мне ужасно оскорбительным.
Вместо этого я стараюсь быть более явным и лучше понимать намерения, моделируя каждую операцию не как метод для отдельного класса Service, а как отдельные классы Command.
public class ChangePasswordCommand {
public Guid MembershipId { get; set; }
public string CurrentPassword { get; set; }
public string NewPassword { get; set; }
}
Тогда что-то должно действительно делать что-то при отправке этой команды, поэтому мы используем обработчики:
public interface IHandle<TMessageType> {
void Execute(TMessageType message);
}
public class ChangePasswordCommandHandler : IHandle<ChangePasswordCommand> {
public ChangePasswordCommandHandler(
IMembershipRepository repo
)
{}
public void Execute(ChangePasswordCommand command) {
var membership = repo.Get(command.MembershipId);
membership.ChangePassword(command.NewPassword);
}
}
Команды отправляются с использованием простого класса, который взаимодействует с нашим контейнером IoC.
Это помогает избежать монолитных классов обслуживания и значительно упрощает структуру и расположение логики проекта.