Lawrence Wagerfield Fragmenting The Heap Since 2000

9Mar/110

Isolating Class Interactions

This post defines 3 horizontal tiers for decoupling code by isolating class interactions within and between packages. Horizontal tiers exist as a contrast to standard tiers (or 'vertical tiers'), which are concerned with isolating levels of service as opposed to class interactions. These horizontal tiers consist of factories, providers and logic, which respectively correlate with creation time, scope management and run time. These facets are expressed as follows:

Factories are responsible for defining the system’s concrete implementations. This is achieved by assigning factory methods to each dependable interface within the system. These methods instantiate concrete implementations and wire their dependencies accordingly, typically via constructor DI.

Providers are responsible for ensuring objects are leased in a way which best suits the system’s scope model. Providers achieve this by wrapping the underlying factories with additional logic which handles the reuse of objects. A provider will invariably call a factory to obtain a new object. However, the provider may then retain said object and return the same instance to subsequent requests, or it may pool them or use any other number of techniques.

Logic defines the implemented method bodies for each of the system’s interfaces. Whilst factories and providers must be initialised on start-up, logic should be called on demand in response to events, such as connection requests or key strokes. Simply put: the logic is the pure runtime code, i.e. what’s left of a method body once creation time and scope management concerns have been removed.

Whilst these tiers promote the use of DI, it is important to note that this design pattern is not always feasible. The first reason is obvious: we must perform at least one call directly to a provider to obtain our first object, which in turn should use DI. This initial call is technically service location and is conceptually unavoidable. The second reason is that objects initialised by third-party components cannot be injected, since they are constructed outside of the controlled environment. Service location must therefore be used as an alternative, but only if the problem cannot be reworked.