Мой код пронизан сервисными интерфейсами! - PullRequest
3 голосов
/ 19 апреля 2009

Привет всем. Я сталкиваюсь со странной схемой проектирования с использованием модели хранилища и сервиса. Приложение состоит из ASP.NET MVC, WCF и некоторых служб Windows. Мои репозитории используют LINQ DataContext. По мере развития моего приложения я обнаруживаю, что везде передаю ссылки на сервис IWhwhatService. Например, у меня есть IAccountService, который определяет такие методы, как ChangePlan (учетная запись, план плана).

Теперь кажется, что IAccountService - лучшее место для использования этого метода, так как мы обслуживаем учетные записи здесь. Однако метод ChangePlan должен знать несколько вещей, прежде чем он сможет реально изменить план. Он должен знать текущее использование пользователя, список доступных планов, экземпляр интерфейса службы электронной торговли для выставления счетов и т. Д.

Я думал, что метод ChangePlan принимает все необходимые службы в интерфейсе IAccountService. Но требование этих других сервисов является вопросом реализации и не должно быть частью определения интерфейса.

Итак, теперь я создаю огромный конструктор для AccountService, использующий экземпляр IAccountRepository, IPlanService, IUsageService, IEcommerceService и IValidationDictionary. Это не совсем правильно.

Теперь возьмите этот сценарий. Очевидно, что IAccountService содержит простой метод для получения учетной записи пользователя по идентификатору: Account Get (int id) Есть несколько раз, когда мне просто нужно вызвать только этот метод. Итак, я иду, чтобы создать свой AccountService, и он хочет, чтобы экземпляры всех этих других служб (особенно IValidationDictionary, мне не нужна проверка для этого). Опять же, это чувствует себя неправильно. Я мог бы передать null, но это только потому, что я знаю, что реализация не использует их только для этого метода.

Кроме того, чтобы не создавать экземпляры служб везде, где они мне нужны, я создал статический класс с именем ServiceFactory, в котором есть статические методы, CreateAccountService, CreatePlanService и т. Д. Я вызываю эти методы во всем приложении. Кажется, все в порядке, но я не могу избавиться от ощущения, что это неправильно.

Где мое отключение здесь? У кого-нибудь есть предложения?

Спасибо.

Andrew

Ответы [ 5 ]

5 голосов
/ 19 апреля 2009

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

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

Я думаю, что ваша главная проблема в том, что вы тратите слишком много времени на размышления о том, как построить этих объектов. Вероятно, вам следует обратиться к инфраструктуре внедрения зависимостей, например Castle Windsor . Тогда вы просто создадите объект в его полном состоянии и не будете беспокоиться о том, что все зависимости не используются для каждого вызова.

1 голос
/ 19 апреля 2009

Так что теперь я создаю огромный конструктор для получения AccountService экземпляр IAccountRepository, IPlanService, IUsageService, IEcommerceService и IValidationDictionary. Это не чувствую себя хорошо на всех.

Подобные зависимости не должны вызывать особого беспокойства. То, на что вы хотите обратить внимание - это огромные методы в вашем AccountService. Если у вас есть методы длиной в сотни строк, то, возможно, пришло время взглянуть на рефакторинг и разделение AccountService на несколько небольших сервисов.

Кроме того, чтобы избежать создания услуги везде, где они мне нужны, я создал статический класс под названием ServiceFactory, который имеет статический методы, CreateAccountService, CreatePlanService и т.д ... Я называю это методы вокруг приложения. кажется нормально, но я не могу избавиться от чувства что это неправильно.

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

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

1 голос
/ 19 апреля 2009

События могут помочь вам отделить хотя бы часть этого. У вас могут быть другие службы, которым необходимо проверить регистр изменений плана в ChangePlanRequestEvent, каждая служба должна выполнить необходимую проверку и выдать исключение, если изменение не разрешено. Теперь у вас есть проблема. Специфика плана должна быть закодирована в объекте «План», и никому не нужен список доступных планов, если вы не хотите их отображать.

Но почему вообще существует AccountService? Для меня, почему ChangePlan не метод учетной записи?

0 голосов
/ 22 апреля 2009

Можете ли вы создать перегруженные конструкторы, которые принимают интерфейсы, необходимые для выполнения базовой операции? Например:

AccountService(IAccountRepository)
AccountService(IAccountRepository, IPlanService)
AccountService(IAccountRepository, IPlanService, IUsageService, IEcommerceService,IValidationDictionary)

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

0 голосов
/ 19 апреля 2009

Я был на том же пути, что и вы, в предыдущих проектах, и мне еще предстоит увидеть чистый подход к решению проблемы. Я думаю, что реальный ответ заключается в том, что SOA вызывает столько проблем, сколько решает. Логика заключается в том, что, отделяя все, что вы можете легко переключать сервисы и их реализации. Однако, если цена, которую мы платим за такую ​​функцию, - это код, который превращается в спагетти-беспорядок интерфейсов, сервисов и внедренных зависимостей, тогда это стоит того - и я говорю, что это не так.

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

...