Factories for Returned Types

Fairly often, we have a class that has a function that returns another class as the result. If the returned type has no logging inside of it, then not much works needs to be done. However, if the returned type does have logging in it, then we need to use an internal factory to create the returned object. In this section we will discuss how to implement explicit factories for returned types.

First, we need to create the factories for the returned type: namespace FunctionalLayer.Factories { public class ReturnedTypeFactory { public virtual ReturnType Construct() { return new ReturnedType(); } } } namespace LoggingLayer.Factories { public class ReturnedTypeFactory : FunctionalLayer.Factories.ReturnedTypeFactory { private ILogger _logger; public ReturnedTypeFactory(ILogger logger) { _logger = logger; } public override ReturnType Construct() { return new LoggingLayer.Objects.ReturnedType(_logger); } } }

Whenever the class that has a function that returns ReturnedType is created, it needs to have access to the returned type factory. The best way to do this is to pass the factory in as a constructor argument. namespace FunctionalLayer.Objects { public class ComplexType { private ReturnedTypeFactory _factory; public ComplexType(ReturnedTypeFactory factory) { _factory = factory; } public virtual ReturnedType FunctionCall() { var returned = _factory.Construct(); ... return returned; } } } namespace LoggingLayer.Objects { public class ComplexType : FunctionalLayer.Objects.ComplexType { private ILogger _logger; public ComplexType(FunctionalLayer.Factories.ReturnedTypeFactory factory, ILogger logger) : base(factory) { _logger = logger; } ... } }

Where this pattern gets more complicated is when we design the factories for the encapsulating class. It's factories need to also have a factory for the returned type. This way, when the outer class is created, it is automatically given the factory for the return type. namespace FunctionalLayer.Factories { public class ComplexTypeFactory { // needs to be protected so the Logging factory may use it. protected ReturnedTypeFactory _returnedTypeFactory; public ComplexTypeFactory() : this(new ReturnedTypeFactory()) {} public ComplexTypeFactory(ReturnedTypeFactory factory) { _returnedTypeFactory = factory; } public virtual ComplexType Construct() { return new ComplexType(_returnedTypeFactory); } } } namespace LoggingLayer.Factories { public class ComplexTypeFactory : FunctionalLayer.Factories.ComplexTypeFactory { private ILogger _logger; public ComplexTypeFactory(ILogger logger) : this(new LoggingLayer.Factories.ReturnedTypeFactory(), logger) {} public ComplexTypeFactory(FunctionalLayer.Factories.ReturnedTypeFactory factory, ILogger logger) : base(factory) { _logger = logger; } public override ComplexType Construct() { // here is where we need access to _returnedTypeFactory return new LoggingLayer.Objects.ComplexType(_returnedTypeFactory, _logger); } } }

Note that the ReturnedTypeFactory is a protected field in the Functional factory; this is necessary since the LoggingLayer factory needs to have access to it. Also, we have two constructors, a default one, and one that takes the ReturnedTypeFactory as an argument.

The default constructor is fine if it is acceptable to simply construct the ReturnedTypeFactory and using it as is.

The constructor that takes the ReturnedTypeFactory has two important reasons to be used:

  • The LoggingLayer Factory needs access to that constructor.
  • If the ReturnedTypeFactory is used inside of multiple classes, then you only need to use one ReturnedTypeFactory and pass it to encapsulating factories.

Next: Daos

Copyright © 2017-2018 Adin H. Baber, all rights reserved.