concept cycle in category dependency injection

appears as: cycle, The cycle, cycles
Dependency Injection

This is an excerpt from Manning's book Dependency Injection.

What we’ve got here is your typical the chicken or the egg causality dilemma. The short answer is that you can’t construct an object graph like this because both classes require the other object to exist before they’re constructed. As long as the cycle remains, you can’t possibly satisfy all Dependencies, and your applications won’t be able to run. Clearly, something must be done, but what?

The cycle in Mary’s object graph appeared once she added the IAuditTrailAppender Dependency to the SqlUserRepository class. Figure 6.13 shows this Dependency cycle.

Figure 6.13 The Dependency cycle involving AspNetUserContextAdapter, SqlUserRepository, and SqlAuditTrailAppender

06-13.eps

The figure shows the cycle in the object graph. The object graph, however, is part of the story. Another view we can use to analyze the problem is the method call graph as shown here:

LazyAuditTrailAppender implements IAuditTrailAppender like SqlAuditTrailAppender does. But it takes its IAuditTrailAppender Dependency through Property Injection instead of Constructor Injection, allowing you to break the cycle without violating the invariants of the original classes. The next listing shows the LazyAuditTrailAppender Virtual Proxy.

Listing 6.31 A LazyAuditTrailAppender Virtual Proxy implementation
public class LazyAuditTrailAppender : IAuditTrailAppender
{
    public IAuditTrailAppender Appender { get; set; }    #1  

    public void Append(Entity changedEntity)
    {
        if (this.Appender == null)    #2  
        {
            throw new InvalidOperationException("Appender was not set.");
        }

        this.Appender.Append(changedEntity);    #3  
    }
}

#1   Property that allows breaking the Dependency cycle
#2   Guard Clause
#3   Forwards the call

Always keep in mind that the best way to address a cycle is to redesign the API so that the cycle disappears. But in the rare cases where this is impossible or highly undesirable, you must break the cycle by using Property Injection in at least one place. This enables you to compose the rest of the object graph apart from the Dependency associated with the property. When the rest of the object graph is fully populated, you can inject the appropriate instance via the property. Property Injection signals that a Dependency is optional, so you shouldn’t make the change lightly.

Dependency Injection in .NET

This is an excerpt from Manning's book Dependency Injection in .NET.

It’s important to realize that the ABSTRACTIONS themselves can be perfectly acyclic, while particular implementation can introduce a cycle. Figure 6.7 shows how this could happen.

Figure 6.7. Cycles in the dependency graph can occur even if the ABSTRACTIONS have no relations to each other. In this example, each implementation implements a separate interface but also requires a DEPENDENCY. Because ConcreteC requires IA, but the only implementation of IA is ConcreteA with its DEPENDENCY on IB and so forth, we have a cycle that can’t be resolved as is.

As long as the cycle remains, we can’t possibly satisfy all DEPENDENCIES, and our applications won’t be able to run. Clearly, something must be done, but what?

In this section, we look into the issue concerning cyclic DEPENDENCIES, including an example. When we’re finished, your first reaction should be to try to redesign your DEPENDENCIES. If that isn’t possible, you can break the cycle by refactoring from CONSTRUCTOR INJECTION to PROPERTY INJECTION. This represents a loosening of a class’s invariants, so it isn’t something you should do lightly.

A DEPENDENCY cycle should immediately trigger a thorough evaluation of the root cause of the cycle. It’s often based on either incorrect assumptions or a serious break of the rule of unidirectional DEPENDENCIES. In a layered application, classes should only talk to other classes in their own layer and the layer immediately below.

If the cycle traverses more than one layer, we know something is fundamentally wrong. As figure 6.8 shows, this would mean that some references go the wrong way.

Figure 6.8. When a cycle crosses one or more layer boundaries, at least one reference is architecturally illegal. In this case, the reference from D to A is the culprit. If a situation like this occurs, it should be addressed immediately.

It’s a little less clear what is going on if we have a cycle within a single layer. This may even be the result of valid considerations that just ended up as less-than-optimal implementations.

It’s imperative that we break a cycle in some way. As long as the cycle exists, the application won’t run.

Any cycle is a design smell, so our first reaction should be to redesign the involved part to prevent the cycle from happening in the first place. Table 6.1 shows some general directions we can take.

Table 6.1. Some redesign strategies for breaking DEPENDENCY cycles

Strategy

Description

Events You can often break a cycle by changing one of the ABSTRACTIONS to raise events instead of having to explicitly invoke a DEPENDENCY to inform the DEPENDENCY that something happened. Events are particularly appropriate if one side only invokes void methods on its DEPENDENCY. .NET events are an application of the Observer[7] design pattern, and you may occasionally consider implementing it explicitly. This is particularly true if you decide to use Domain Events[8] to break the cycle. This has the potential to enable true asynchronous one-way messaging.
PROPERTY INJECTION If all else fails, we can break the cycle by refactoring one class from CONSTRUCTOR INJECTION to PROPERTY INJECTION. This should be a last-ditch effort because it only treats the symptoms.

You should only resort to solving cycles by using PROPERTY INJECTION as a last-ditch effort. It only treats the symptoms instead of curing the illness.

To break the cycle, we must analyze it to figure out where we can make a cut. Because using PROPERTY INJECTION suggests an optional rather than a required DEPENDENCY, it’s important that we closely inspect all DEPENDENCIES to determine where cutting hurts the least.

In figure 6.9, B requires an instance of IC (the interface that C implements). We can resolve the cycle by changing B’s DEPENDENCY from CONSTRUCTOR INJECTION to PROPERTY INJECTION. This means that we can create B first and inject it into A, and then subsequently assign C to B:

var b = new B();
var a = new A(b);
b.C = new C(new D(a));
Figure 6.9. Given a cycle, we must first decide where to cut it. In this case, we decide to cut between B and C.
sitemap

Unable to load book!

The book could not be loaded.

(try again in a couple of minutes)

manning.com homepage
test yourself with a liveTest