2010-06-25 8 views
7

Предположим, вы делите свои системы в Value объектов и служб объектов (как это было предложено в «Growing объектно-ориентированного программного обеспечения, руководствуясь Tests». Мисько Hevery называет эти «newables» и «уколы».Инъекция зависимостей, когда созданный класс также требует значений времени выполнения?

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

Предположим, у вас есть хороший простой объект Value. Он неизменен, содержит несколько бит информации, и все об этом. Скажем, мы используем его как-то вроде это:

CreditCard card = new CreditCard("4111-1111-1111-1111", "07/10"); 
if (card.isValid()) 
{ 
    // do stuff 
} 
else 
{ 
    // don't do stuff 
} 

Пока все хорошо. isValid() реализует алгоритм контрольной цифры на номере карты и возвращает true/false.

Теперь предположим, что я хочу улучшить систему, подтвердив дату истечения срока действия текущего времени. Как вы предлагаете это сделать, не нарушая объект Value/Service object paradim? Я бы хотел, чтобы этот класс оставался единым проверяемым.

  • CreditCard теперь имеет зависимость, но из-за способа его создания его нельзя вводить, поэтому инъекция зависимостей отсутствует.
  • CreditCard класс не должен быть взывает к Одиночки (я придерживаюсь позиции, что глобальный доступ к Singleton является плохой практикой)
  • Положив поведение на CreditCardVerificationService.validateCard() означает, что все существующий код должен быть пересмотрен. Выполняется реализация isValid().

Я знаю, что есть вещи, которые можно сделать, чтобы обойти это, но что является самым чистым способом?

ответ

4

Я бы сказал, что это не задача объекта CreditCard проверять что-либо. Завод будет проверять контрольные цифры, чтобы убедиться, что он создает экземпляр соответствующей карточки, в то время как служба проверки будет проверять карту на срок действия/лимит.

+0

Интересно. Мне кажется естественным, что поведение (валидация) должно соответствовать данным, а не объекту CreditCard. –

+4

Это превращает реальный мир в его голову. У кредитной карты нет никакого способа проверить себя - подделанные, просроченные карты живут в дикой природе и не имеют представления о том, являются ли они действительными или нет. Если вы отправите запрос платежному процессору, они не будут спрашивать вас, действительна ли ваша карта или занять свое слово - они сами это определит и просто запросят данные, необходимые для этого. – expedient

+0

@WW: Также Роберт К. Мартин «Дядя Боб» рассказывает об этом при описании принципа единственной ответственности SOLID в своем примере модема (6-страничная статья: http://www.objectmentor.com/resources/articles/srp.pdf). Я думаю, что в прошлом CreditCard.Validate() считался бы хорошим объектно-ориентированным дизайном, но эта тенденция, похоже, отходит от многих отдельных классов. Также я задал вопрос об этом на ProgrammersSE http://programmers.stackexchange.com/questions/77690/design-object-method-vs-separate-classs-method-which-takes-object-as-parameter – User

1

У меня возникло бы желание сказать, что CreditCard - это не объект ценности.

От C2 wiki:

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

Объект значения не является Объектом BusinessObject/ReferenceObject. A BusinessObject/ReferenceObject - что-то, что вы найдете в мире, а ValueObject - это мера или описание чего-то.

Если CreditCardNumber может быть значение объекта, CreditCard больше похож на бизнес-объект, который содержит некоторые бизнес-логику, например, Проверка.

Обычно у меня есть объект Value, Service и Business Object. Я не знаю о «Growing Object-Oriented Software», но ограничивать себя только Value Object и Service кажется мне странным.

+0

Так что если CreditCard является бизнес-объектом, как бы вы справились с ситуацией в вопросе? –

+0

@WW Я предлагаю вам взглянуть на «Domain Driven Design». В этом есть много ресурсов. Ниже приведено обсуждение DDD на примере кредитной карты http://misko.hevery.com/2009/03/16/design-for-testability-and-domain-driven-design/ – ewernli

0

Я бы назвал CreditCard в объект, а не объект в значение, так как это, вероятно, быть стойким и иметь уникальный идентификатор.

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

Если реализация сервиса делает необходимости быть выбран во время выполнения, чем Service Locator может быть использована. Этот шаблон может обеспечить прямую поддержку насмешек/подделок, без необходимости использования специализированного инструмента для издевательств. Другой альтернативой может стать использование каркаса DI, поддерживающего инъекцию в «новые» объекты.