Factories with Initialization

If the factory is going to handle the actual initialization of the object, then we take a slightly different approach. We want to separate the construction from the initialization, which in turn allows us to reuse the initialization code in the Traceable Layer. If there is no need to ever construct the class outside of the factory, then we may even make the Construct() call protected. namespace FunctionalLayer.Factories { public class InitializedClassFactory { public InitializedClass ConstructFromDataStream(DataStream stream) { var initializedClass = Construct(); // initialize from stream ... return initializedClass; } protected virtual InitializedClass Construct() { return new InitializedClass(); } } }

Note that ConstructFromDataStream() is not virtual. Since we want to use the same initialization sequence in both layers, we don't have any need to override it.

Now, all we need to do to implement the Traceable Layer factory is add the Tracer property and override the Construct() call. namespace TraceableLayer.Factories { public class InitializedClassFactory : FunctionalLayer.Factories.InitializedClassFactory { private Tracer _tracer; public InitializedClassFactory(Tracer tracer) { _tracer = tracer; } protected override InitializedClass Construct() { return new TraceableLayer.Entities.InitializedClass(_tracer); } } }

When ConstructFromDataStream() is called, the Traceable Layer factory will still use the initialization code, but will instead produce a Traceable object. Once again, inheritance saves us an enormous amount of work.

What makes this pattern even more enticing is that the Functional Layer factory could have several more initializing functions, but if they all used the same Construct() call, then the Traceable Layer factory would not change from above. namespace FunctionalLayer.Factories { public class InitializedClassFactory { public InitializedClass ConstructFromDataStream(DataStream stream) { var initializedClass = Construct(); // initialize from stream ... return initializedClass; } public InitializedClass ConstructFromDifferentDataStream(DifferentDataStream stream) { var initializedClass = Construct(); // initialize from stream ... return initializedClass; } public InitializedClass ConstructFromYetAnotherDataStream(YaDataStream stream) { var initializedClass = Construct(); // initialize from stream ... return initializedClass; } protected virtual InitializedClass Construct() { return new InitializedClass(); } } } namespace TraceableLayer.Factories { public class InitializedClassFactory : FunctionalLayer.Factories.InitializedClassFactory { // exactly the same as prior Traceable factory example } }

Factories with Wrapped Initialization Logic

We may have situations where the initialization functions generates chaff much like the Copy() method did as shown in Traceable Layer. The most likely reason for this to happen is that existing instance are being copied, or that values from existing Traceable objects are being used. In this case, we can follow the same pattern in the Copy() method, and wrap the initialization method to remove the chaff. namespace FunctionalLayer.Factories { public class InitializedClassFactory { public virtual InitializedClass ConstructFromDataStream(DataStream stream) { var initializedClass = Construct(); // initialize from stream return initializedClass; } protected virtual InitializedClass Construct() { return new InitializedClass(); } } } namespace TraceableLayer.Factories { public class InitializedClassFactory : FunctionalLayer.Factories.InitializedClassFactory { private Tracer _tracer; public InitializedClassFactory(Tracer tracer) { _tracer = tracer; } public override InitializedClass ConstructFromDataStream(DataStream stream) { _tracer.OpenNode(“IgnoreInitialization”); var initializedClass = base.ConstructFromDataStream(stream); _tracer.CloseAndRemoveNode(); return initializedClass; } protected override InitializedClass Construct() { return new TraceableLayer.Entities.InitializedClass(_tracer); } } }

Next: Factories For Returned Types