Builder Part 2

As a refresher, here is the high level overview of my Builder library:

01456029fae1a4166121daf5e0910aa377fd51a8ff

What’s not on this diagram are the base classes that correspond to each interface. I left the base classes off to simplify the diagram, but, I’ll cover them in this article so, no worries.

BuilderBase

In the last article I promised to that I would demonstrate how the Builder does what it does. I think a good place to start is with the BuilderBase class. That’s where most of the action takes place. The purpose of the BuilderBase is to be a base class for any concrete Builder class, or to be a reusable Builder object for those cases where a concrete Builder type isn’t needed, or perhaps isn’t possible.

Here is a trimmed down code listing:

The first thing to note about the BuilderBase class is that it implements the IBuilder interface, from the diagram. The class contains an internal collection of external Providers, which it initializes through several of the overloaded constructors. Those ctor overloads make it possible to embed a Builder within an existing Product, and have that Builder automatically share the collection of Providers with the Product. That means everything can be configured by the top-level Builder, and any child Builders will share the resulting Setup and Provider objects without any further intervention.

The generic Build method accepts no parameters other than the single typedef. This is the method that kicks off the build process. Note that the method calls the protected virtual OnBuild method, passing in the typedef parameter from the caller and returning the resulting IBuilderProduct reference. This arrangement, with the actual implementation of the Build method resting in the protected virtual OnBuild method, means that, for the 99% of builders who won’t need any additional building logic, nothing else need be done. However, for the 1% that might need to override the existing logic, they can do that by simply deriving from BuilderBase and overriding OnBuild.

The OnBuild method itself is where the building process takes place. The Builder starts by using the .NET Activator to create an instance of the Product class. Obviously, this implies that all Product classes should have a default constructor. That might seem limiting at first glance but, with the collection of Providers that will be created and injected shortly, there’s plenty of opportunity to pass in additional information and resources to the Product, without adding parameters to a constructor.

Once the Product instance exists, the Builder loops through any external Providers it’s currently referencing and adds them to the Product’s collection of Providers.

Next, the Builder loops through any Setups that were added to the Builder by the caller. Each Setup is then asked to create an instance of it’s corresponding Provider type. As each Provider object is created it is then added to the Product’s collection of Providers.

Finally, the Initialize method on the Product is called, to provide the Product with the opportunity to construct itself from the various Providers that were been supplied by the Builder.

Finally, the populated, configured and initialized Product instance is returned to the caller.

BuilderSetupBase

After the BuilderBase class, the BuilderSetupBase class is the most interesting. The purpose of the BuilderSetupBase class is to: (1) provide a base for all concrete Setup classes, and (2) create a relationship between a concrete Provider, and a concrete Setup. That relationship is important because, in addition to holding configuration information, Setups are also Builder’s in their own right. As I mentioned before, Setups are charged with creating their corresponding Provider during the Build operation.

Here is a trimmed down code listing:

The first thing to note about the BuilderSetupBase class is that it implements the IBuilderSetup interface, from the diagram. The class contains a property named Children, which contains a collection of IBuilderSetup objects as well. This is the collection of child Setups I spoke about earlier.

Just like in the BuilderBase class, the Build method calls a protected virtual method named OnBuild. Unlike the BuilderBase though, these two methods are not generic, so there’s no typedef parameter. The virtual OnBuild method is there to make it easier to override the default build behavior for a Setup, in that 1% scenario where that would come in handy. Both the Build and the OnBuild methods accept a reference to the Builder instance. That made sense to me when I did it but now that I write about it … Pffft! Anyway, there is a reference to the Builder if you need it. I’m sure I had some good reason for putting it there …

Inside the OnBuild method, the first step is to create the Provider instance using the typedef “TProvider” parameter, from the class definition. So, just like in the BuilderBase, with the Product type, we’re making an assumption here that all Provider types have a public default constructor. Once again, I think that’s a reasonable assumption considering the provider will have it’s associated Setup instance available, at runtime. That assignment is performed right after the Provider instance is created.

After the Provider object is created, the Setup then iterates through the Children collection and builds any child Provider objects as well. As each child Provider is created, it is immediately placed into the parent Provider’s collection of child Providers.

After the Provider object, and any children are created and added, the reference is returned to the caller. That’s pretty much it, for Setup.

BuilderProviderBase

The next most interesting piece is the BuilderProviderBase class. The purpose of this class is to create a base for all concrete Provider classes.

Here is a trimmed down code listing:

The first thing to take note of is that the BuilderProviderBase class implements the IBuilderProvider interface, from the diagram. The class also derives from the DisposableBase class, which is a class I use to encapsulate the .NET “disposable pattern”.

The class contain a Setup property that holds a reference to the associated Setup. This reference is setup by the Setup, when the Provider object is created.

The class also contains a Children property, that holds a collection of IBuilderProvider instances. This collection is also built by the Setup object, during build time.

Finally, the class takes care of cleaning up any disposable Providers in the Children collection.

BuilderProductBase

The final piece of the library is the BuilderProductBase class. The purpose of this class is to created a base for all concrete Product types.

Here is a trimmed down code listing:

The firs thing to note is that the BuilderProductBase class implements the IBuilderProduct interface, from the diagram. The class also derives from the DisposableBase class, just like the BuilderProviderBase class.

The class contains the Providers property, with the collection of IBuilderProvider instances that have been created by the Builder.

There is also the Initialize method, which accepts a reference to the Builder for a reason that escapes me as I write this. Just like in the BuilderSetupBase class though, I’m sure I had some reason for passing that reference around … *shrugs*

The Initialize method follows the same pattern I established with the Build methods, in that it internally calls a protected, virtual method calls OnIniitalize. Concrete providers can override that OnInitialize method if they need to respond by initializing themselves. It’s not abstract though, so, it’s not required.

Finally, the class loops through any disposable Providers and cleans those up during the disposal process.

Extension methods

In addition to the interfaces and base classes, there are a few extension classes as well. Let’s walk through those and see what they offer.

GuardExtensions

The GuardExtensions class extends the capabilities of the Guard class, which is a class that I use to perform basic parameter checks and the like. GuardExtensions contains the following methods:

* ThrowIfCircularReference – which is used to ensure that none of the child Setup or Provider instances create a nasty circular reference. If one is detected then an ArgumentException is thrown.

* ThrowIfMissingProperties – which is used to validate that a Setup with nullable property types has valid, non-null values placed into them. This method is called for each Setup added to a Builder, as part of the build process. The purpose of this is, to ensure that any mandatory Setup properties have some sort of workable default value in them. That means if a property on a Setup has a nullable return type (including string), then it needs to have some sort of default value in the concrete Setup class, or one supplied by the caller, or the Build process will be aborted. Not that this only affects Setup properties with nullable return types. Non-nullable return types are ignored.

IBuilderProductExtensions

The IBuilderProductExtensions class is used to extend the capabilities of the IBuilderProduct interface. The class contains the following methods:

* FindProvider – which is used to locate a given Provider instance in the collection of Providers, for a given Product. The search is performed like this: The immediate collection of Providers is searched, then the immediate children of those Providers is searched. Nothing below the child level is searched though, just as an arbitrary limit, since I can’t foresee any reason for that many levels of Providers.

* FindProviders – which is used to locate a given collection of Provider instances in the collection of Providers, for a given Product. The search is performed like this: The immediate collection of Providers is searched, then the immediate children of those Providers is searched. Nothing below the child level is searched though … Just as an arbitrary limit, since I can’t foresee any reason for that many levels of Providers.

IBuilderProviderExtensions

The IBuilderProviderExtensions class is used to extend the capabilities of the IBuilderProvider interface. The class contains the following methods:

* FindSetup – which is used to locate a given Setup instance for a given Product. The search is performed like this: The Setup associated with the Provider is checked, then the immediate collection of child Setups is checked. Nothing below the child level is searched though … Just as an arbitrary limit, since I can’t foresee any reason for that many levels of Setups.

* FindSetups – which is used to locate a collection of Setup instances for a given Product. The search is performed like this: The Setup associated with the Provider is checked, then the immediate collection of child Setups is checked. Nothing below the child level is searched though … Just as an arbitrary limit, since I can’t foresee any reason for that many levels of Setups.

IBuilderSetupExtensions

The IBuilderSetupExtensions class is used to extend the capabilities of the IBuilderSetup interface. The class contains the following methods:

* DumpProperties – which actually isn’t used at all in this package, although, it is used by other packages. The method iterates through all the methods on a Setup type, using reflection, and finds a collection of methods that start with “Get”, are public, and return a nullable type. Once that collection is built, it is then iterated through and a string is generated containing each method and it’s associated return value. The point of the method is to quickly dump a configuration for any Setup and I used it to log start values for services and the like.

Using the Builder

I’ll tackle this next time, when I’ll lay out several different strategies for using the Builder library.

Check back!