Reputation: 655
I have a factory which creates objects that are widely used through my application. Some of the objects the factory creates require another dependency. This optional dependency is an interface/class with settings from a local settings file. Currently both the factory interface AND the settings interface are injected into something like 20 classes. Albeit, the number of classes would be less if the applications inheritance tree wasn't about 6-7 levels deep (meaning the IFactory and ISettings get passed through 6 constructors and finally arrive at a base class which assigns them to a field).
The deep inheritance isn't getting changed anytime soon, but I thought that I could lessen the load of these constructors by removing the ISettings from them and putting it in the IFactory implementation itself. The ISettings would be injected into the concrete factory through the constructor, and then instead of passing the ISettings as a part of the Create() method, it would just use the factory ISettings readonly property. These settings are guaranteed to be immutable once the program starts.
Is this frowned upon in any way, and are there better ways of going about this? Some coworkers think that Factories should almost never hold state...but they aren't exactly sure why.
These are similar questions that I found, that gave answers but I'm still looking for a more fleshed out answer if possible.
Adding Properties to Abstract Factory
Abstract Factory Pattern and Properties
Simple example:
interface IObjValidator
{
bool Validate();
}
interface IObjValidatorFactory
{
IObjValidator Create();
}
class ObjValidatorFactory : IObjValidatorFactory
{
// Is it OK for the factory to hold this field?
private readonly ISettings settings;
public IObjValidator(ISettings settings)
{
this.settings = settings;
}
IObjValidator Create(ObjValidatorMode mode)
{
switch(mode)
{
case ObjValidatorMode.One:
return ObjValidator1();
case ObjValidatorMode.Two:
return ObjValidator2(this.settings);
}
}
}
class ObjValidator1: IObjValidator
{
public bool Validate()
{
// Do stuff.
}
}
class ObjValidator2: IObjValidator
{
private readonly ISettings settings;
public ObjValidator2(ISettings settings)
{
this.settings = settings;
}
public bool Validate()
{
// Use ISettings field data here.
}
}
Upvotes: 1
Views: 110
Reputation: 15212
Is this frowned upon in any way, and are there better ways of going about this?
An incorrect approach to solving this problem would be to have a Singlteon settings class that the validators access using Settings.getInstance
. This is what would be frowned upon. The approach mentioned in the question actually tackles all the issues that a singleton settings class would have introduced and is is therefore the right way forward.
That said, one thing I would change is that I would make the ObjValidatorFactory
class depend on an ISettingsFactory
interface rather than depending on ISettings
directly. This would redirect the responsibility of creating an ISettings
implementation from the client class to ObjValidatorFactory
.
class ObjValidatorFactory: IObjValidatorFactory
{
private ISettingsFactory settingsFactory;
public ObjValidatorFactory(ISettingsFactory settingsFactory)
{
this.settingsFactory = settingsFactory;
}
IObjValidator Create(ObjValidatorMode mode)
{
//source could be the file name for example
ISettings settings = settingsFactory.Create(source);
switch(mode)
{
case ObjValidatorMode.One:
return ObjValidator1();
case ObjValidatorMode.Two:
return ObjValidator2(settings);
}
}
}
The factory could be instantiated as follows :
ISettingsFactory fileSettingsFactory = new FileSettingsFactory();
IObjValidatorFactory objectValidatorFactory = new ObjValidatorFactory(fileSettingsFactory);
objectValidatorFactory.Create(ObjValidatorMode.STRICT);
Upvotes: 1
Reputation: 603
Few observations: - Not all validators require ISettings - Object is created based on mode
In this case, I think that Abstract factory suits more, delegating responsibilities to child classes.
It is ok to have fields in Factory class which will be responsible for factoring the same object, think of a biscuit factory always creating a same biscuit.
The way, you have defined the factory class, can lead to content coupling. In future, you will start injecting more and more dependencies which will not be maintainable.
Another way could be to inject the pre-built validators as a map in the factory and on create() , get an entry from the map.
Upvotes: 0
Reputation: 546
I'd rather avoid that if I could, everything else being equal, if ObjValidator2 was somehow replaced with a different validator (e.g. ObjValidator2a),
A.) you would now have to change your constructor to accept a settings object for objValidator2a B.) drop it from the constructor because objValidator2a does not need settings for objValidator2 C.) keep the constructor as is knowing that the setting passed will never be used.
YMMV
Upvotes: 1