17

As part of an overall S.O.L.I.D. programming effort I created a factory interface & an abstract factory within a base framework API.

People are already starting to overload the factories Create method. The problem is people are overloading the Create method with model properties (and thereby expecting the factory to populate them).

In my opinion, property setting should not be done by the factory. Am I wrong?

public interface IFactory
{
    I Create<C, I>();
    I Create<C, I>(long id); //<--- I feel doing this is incorrect

    IFactoryTransformer Transformer { get; }
    IFactoryDataAccessor DataAccessor { get; }
    IFactoryValidator Validator { get; }
}

UPDATE - For those unfamiliar with SOLID principles, here are a few of them:

Single Responsibility Principle
It states that every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class

Open/Closed Principle
The meaning of this principle is that when a get a request for a feature that needs to be added to your application, you should be able to handle it without modifying old classes, only by adding subclasses and new implementations.

Dependency Inversion Principle
It says that you should decouple your software modules. To achieve that you’d need to isolate dependencies.

Overall:
I'm 90% sure I know the answer. However, I would like some good discussion from people already using SOLID. Thank you for your valuable opinions.

UPDATE - So what do I think a a SOLID factory should do?

IMHO a SOLID factory serves-up appropriate object-instances...but does so in a manner that hides the complexity of object-instantiation. For example, if you have an Employee model...you would ask the factory to get you the appropriate one. The DataAccessorFactory would give you the correct data-access object, the ValidatorFactory would give you the correct validation object etc.

For example:

var employee = Factory.Create<ExxonMobilEmployee, IEmployee>();
var dataAccessorLdap = Factory.DataAccessor.Create<LDAP, IEmployee>();
var dataAccessorSqlServer = Factory.DataAccessor.Create<SqlServer, IEmployee>();
var validator = Factory.Validator.Create<ExxonMobilEmployee, IEmployee>();

Taking the example further we would...

var audit = new Framework.Audit(); // Or have the factory hand it to you
var result = new Framework.Result(); // Or have the factory hand it to you

// Save your AuditInfo
audit.username = 'prisonerzero';

// Get from LDAP (example only)
employee.Id = 10;
result = dataAccessorLdap.Get(employee, audit);
employee = result.Instance; // All operations use the same Result object

// Update model    
employee.FirstName = 'Scooby'
employee.LastName = 'Doo'

// Validate
result = validator.Validate(employee);

// Save to SQL
if(result.HasErrors)
     dataAccessorSqlServer.Add(employee, audit);

UPDATE - So why am I adamant about this separation?

I feel segregating responsibilities makes for smaller objects, smaller Unit Tests and it enhances reliability & maintenance. I recognize it does so at the cost of creating more objects...but that is what the SOLID Factory protects me from...it hides the complexity of gathering and instantiating said objects.

Prisoner ZERO
  • 13,848
  • 21
  • 92
  • 137
  • 3
    how is this not constructive? – codingbiz Jan 04 '13 at 14:56
  • Why exactly do you feel that it is wrong for a factory to do that? Say you want the factory to create an instance X with property Y, but only if such an X does not already exist. If it already exists, you can use the existing instance, which might be cached within the factory. Are there significant downsides to this? – Kjartan Jan 04 '13 at 14:58
  • It's not that it isn't constructive. I'm more under the impression that something else populates objects...not the factory. My interpretation of reading is: the factory is used to encapsulate the complexity of object creation...not object population. Something else should be used in populating model and accessing data...not the factory. – Prisoner ZERO Jan 04 '13 at 14:58
  • Please remember I am talking in terms of practices and principles related to Agile SOLID programming. Not in terms of what people did BEFORE S.O.L.I.D. came to exist. – Prisoner ZERO Jan 04 '13 at 14:59
  • 1
    what SOLID principle is violated by passing `id` to `Create` method? SPR? – Ilya Ivanov Jan 04 '13 at 15:02
  • 9
    if the factory does not populate the object, what does it do? (except for going var foo = new Foo(); ? I might be wrong, but I don't understand what you are doing in the factory? – ruffen Jan 04 '13 at 15:21
  • To give a real world analogy - a car factory both creates and populates properties of car objects that roll off the production line. If it only created them you would have cars without interior fittings, wheels or a paint job. – levelnis Jan 04 '13 at 15:27
  • I am open to discussion...but IMHO "SOLID" factories do not do data-access, transformation or validation for you. They merely hide the complexities of instantiation without concern as to data-access or population of models. You certainly may have a DataAccess factory, you certainly may have a Transformer factory...but the DataAccess instance (itself) does the data-access...the factory merely serves-up type instances to you. – Prisoner ZERO Jan 04 '13 at 18:46
  • 1
    Can you better define the 'complexities' you're attempting to hide? I've found that a lot of devs lump all creational patterns into a 'Factory Pattern' classification. It sounds like you've designed an abstract factory so consumers have no knowledge of concrete types (of type `I`), while others on your team are treating your factories as either builders or repositories (a facade pattern). If your intention is for factories to only 'new' up an object, you might want to document that a little more clearly or otherwise convey that to your team. – Joseph Yaduvanshi Jan 04 '13 at 20:06
  • @Jim Schubert That is correct. The factory will 'new up' the correct instance using the model (as reference). It will give the consumer the correct DataAccessor or Validator or whatever. Further processing is then delegated to said models given Transformer, Validator or whatever. – Prisoner ZERO Jan 04 '13 at 20:29

3 Answers3

8

I'd say it's sticking to DRY principle, and as long as it's simple values wiring I don't see it being problem/violation. Instead of having

var model = this.factory.Create();
model.Id = 10;
model.Name = "X20";

scattered all around your code base, it's almost always better to have it in one place. Future contract changes, refactorings or new requirements will be much easier to handle.

It's worth noting that if such object creation and then immediately properties setting is common, then that's a pattern your team has evolved and developers adding overloads is only a response to this fact (notably, a good one). Introducing an API to simplify this process is what should be done.

And again, if it narrows down to simple assignments (like in your example) I wouldn't hesitate to keep the overloads, especially if it's something you notice often. When things get more complicated, it would be a sign of new patterns being discovered and perhaps then you should resort to other standard solutions (like the builder pattern for example).

k.m
  • 30,794
  • 10
  • 62
  • 86
  • Great comment, Jimmy! I completely agree with delegating the data-access & model-population portions to another object. I also agree a builder pattern may be another way to do that (I use what I call a DataAccessor). I've tried "burying" the factory into "builders" and found it creates unnecessary dependency between the DataAccesser and the factory (why not pass the model into the builder instead). Any thoughts on that? – Prisoner ZERO Jan 04 '13 at 18:54
  • +1 because I always love that `GetPizza()` example on Wikipedia... and because I agree the builder pattern is where @PrisonerZERO's team is heading. – Joseph Yaduvanshi Jan 04 '13 at 20:10
  • 1
    @PrisonerZERO: of course, you could pass model to builder. But that creates yet another pattern I'm sure your devs will quickly pick on: *"grab object from factory and immediately pass it to builder"* - two steps, instead of one (and I believe that's what they were "fighting" against with introduction of overloads to your factory - see my edit). Also, doesn't factory already depend on DA-component? – k.m Jan 04 '13 at 20:41
  • @jimmy_keen The concrete factory does understand other concrete instances...but at some point in time something must. That is the exact purpose of the concrete factory (to 'new' up the correct instance required for a given model). And...I "feel' this is where that kind of logic is "best placed". But I enjoy seeing what others do, as well. – Prisoner ZERO Jan 04 '13 at 20:49
2

Assuming that your factory interface is used from application code (as opposed to infrastructural Composition Root), it actually represents a Service Locator, which can be considered an anti-pattern with respect to Dependency Injection. See also Service Locator: roles vs. mechanics.

Note that code like the following:

var employee = Factory.Create<ExxonMobilEmployee, IEmployee>();

is just syntax sugar. It doesn't remove dependency on concrete ExxonMobilEmployee implementation.

You might also be interested in Weakly-typed versus Strongly-typed Message Channels and Message Dispatching without Service Location (those illustrate how such interfaces violate the SRP) and other publications by Mark Seemann.

Roman Boiko
  • 3,576
  • 1
  • 25
  • 41
  • Note: I would use factories when it is not possible to create an instance without some information which is unavailable until that instance has to be created. Such information would be passed via parameters to the factory method. The factory itself would be provided as a dependency to the consumer by a DI container. The factory interface would likely be very simple, often with only a single strongly-typed method; alternatively, it could be just a `Func<...>` instance. – Roman Boiko Jan 04 '13 at 23:47
  • An interesting series of posts was recently written by Ayende. In particular, I recommend reading http://ayende.com/blog/159363/design-patterns-in-the-test-of-time-factory-method and http://ayende.com/blog/159362/design-patterns-in-the-test-of-time-builder – Roman Boiko Jan 04 '13 at 23:58
  • 1
    I enjoyed each article very much! Oddly enough the author doesn't offer-up viable alternatives to the code examples listed. My classes follow the "Consumer" or "RegisterUserConsumer" patterns he mentions pretty closely. As such, it currently isn't possible to create "Send(new Foo())". Plus, I don't mix-in other responsibilities into my method calls...unless a publicly available interface is passed into the constructor. Send more articles! Thanks! :) – Prisoner ZERO Jan 05 '13 at 00:17
  • Mark has viable alternatives. I didn't have much time to filter the best posts, just picked up what I remembered as somehow relevant. I encourage reading from them more, many of their posts are brilliant. – Roman Boiko Jan 05 '13 at 00:30
  • The "Abstract Factory" is EXACTLY what I am doing for the DataAccessor, Validator and Transformer factories. I will have to put more thought into the root though. Thanks again! – Prisoner ZERO Jan 05 '13 at 00:33
  • 1
    APIs like `Factory.Validator.Create()` assume that any types could be substituted when calling this method. See also Mark's post on differences between Locator and Abstract Factory. Also, as I mentioned already, you might want to avoid static dependency on `ExxonMobilEmployee`. – Roman Boiko Jan 05 '13 at 00:37
  • So...how do you tell the difference between a valid "Composition Root" and an invalid "Service Locator" ? Both seem very factory-like. My factory follows his definition of "A unique location in an application where modules are composed together". However, I agree with you this also has an anti-pattern "feel" to it...in that...if you request objects that are undefined it will throw an runtime error (it purposefully throws the error). Conceptually...'newing' up has value! So, what is the solution? – Prisoner ZERO Jan 05 '13 at 01:33
  • Composition Root has to be at the entry point of application. E.g., in the `main()` for console applications. It is responsible only for wiring up various classes together, no business logic should be there. Mark's book has excellent collection of DI patterns and anti-patterns. Many of those are also described in detail on his blog. In most cases, libraries don't need to have Composition Root themselves, they delegate this responsibility to the application which uses them. – Roman Boiko Jan 07 '13 at 21:16
0

After about 6 months of experience in Dependency Injection, I've only discovered few cases where factories should set properties:

  1. If the setter is marked as internal, and the properties are expected to be set once by the factory only. This usually happens on interfaces with only getter properties whose implementations are expected to be created thru a factory.

  2. When the model uses property injection. I rarely see classes that use property injection (I also try to avoid building these), but when I do see one, and the needed service is only available elsewhere, it's a case where you have no choice.

For the bottom line, leave public setters out of factories. Only set properties that are marked as internal Let the clients decide on what properties they need to set if they are allowed to do so. This will keep your factories clean of unneeded functions.

stromms
  • 161
  • 5