Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency injection when the class created also needs runtime values?

Assume you divide up your systems in Value objects and Services objects (as suggested in "Growing Object-Oriented Software, Guided by Tests". Misko Hevery calls these "newables" and "injectables".

What happens when one of your value objects suddenly needs to access a service to implement it's methods?

Let's say you have a nice simple Value object. It's immutable, holds a few bits of information and that's about it. Let's say we use it something like this:

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

So far so good. isValid() implements a check digit algorithm on the card number and returns true/false.

Now, let's say I wish to enhance the system by validating the expiry date against the current time. How would you suggest this is done without breaking the Value object/Service object paradim? I should like this class to continue to be unit testable.

  • CreditCard now has a dependency, but because of the way it is created it can not be injected, so dependency injection is out.
  • The CreditCard class should not be calling out to Singletons (I am of the position that global access to a Singleton is bad practice)
  • Putting the behaviour on CreditCardVerificationService.validateCard() means all the existing code has to be revisited. The implementation of isValid() is leaking out.

I know there are things that can be done to get around this, but what is the cleanest way?

like image 455
WW. Avatar asked Jun 25 '10 12:06

WW.


People also ask

What is runtime dependency injection?

Runtime dependency injection allows for advanced configuration of services during runtime rather than needing to decide what services your application will use at compile time.

What does dependency injection require?

Dependency injection is a programming technique that makes a class independent of its dependencies. It achieves that by decoupling the usage of an object from its creation. This helps you to follow SOLID's dependency inversion and single responsibility principles.

When should dependency injection be used?

More specifically, dependency injection is effective in these situations: You need to inject configuration data into one or more components. You need to inject the same dependency into multiple components. You need to inject different implementations of the same dependency.


2 Answers

I would argue that it isn't a CreditCard object's job to validate anything. A factory would validate the check digits to ensure that it is instantiating a conforming card, while a verification service would validate the card for expiration/$ limit.

like image 85
expedient Avatar answered Oct 20 '22 12:10

expedient


I would be tempted to say that CreditCard is not a Value Object.

From the C2 wiki:

Examples of value objects are things like numbers, dates, monies and strings. Usually, they are small objects which are used quite widely. Their identity is based on their state rather than on their object identity. This way, you can have multiple copies of the same conceptual value object.

A value object is not a BusinessObject/ReferenceObject. A BusinessObject/ReferenceObject is something you find in the world, while a ValueObject is a measure or description of something.

If CreditCardNumber could be a value object, CreditCard looks more like an business object which contains some business logic, e.g. validation.

I usually have Value Object, Service and Business Object. I don't know about "Growing Object-Oriented Software", but restricting yourself to only Value Object and Service seems odd to me.

like image 39
ewernli Avatar answered Oct 20 '22 13:10

ewernli