- 75.5k
- 18
- 194
- 467
If TTree
doesn't have a parameterless constructor, then the generic concrete factory has a problem:
public class TreeFactory<TTree> : ITreeFactory<TTree>
where TTree : ITree
{
public ITree Create<TTree>()
{
return new ????(); // so, what type is TTree? how do we pass ctor parameters?
}
}
That can't work! This is where the enum type kicks in, when the type of the factory's product is unknown at compile-time - now because each tree type might have different constructor arguments, abstracting them into their own type can simplify things:
public class TreeFactory : ITreeFactory
{
private readonly IDictionary<TreeType, Func<ITreeArgs,ITree>> _create;
public TreeFactory(IDictionary<TreeType, Func<ITreeArgs,ITree>> factoryMethods)
{
_create = factoryMethods;
}
public ITree Create(TreeType treeType, ITreeArgs args)
{
return _create[treeType](args);
}
}
Where ITreeArgs
could perhaps encapsulate an object
that merely exposes an array of constructor arguments, whatever they are. Notice that the factory class itself doesn't even know/care how each TreeType
gets created - it receives a dictionary of factory methods (one for each TreeType
) and simply calls into it in the Create
method; this means if you want to modify how this factory class generates such or such ITree
implementation, you don't even need to change the factory class's code!
This is probably overkill for your example code however, since all your ITree
implementations seem to have a default constructor, therefore the generic factory would work.
If TTree
doesn't have a parameterless constructor, then the generic concrete factory has a problem:
public class TreeFactory<TTree> : ITreeFactory<TTree>
where TTree : ITree
{
public ITree Create<TTree>()
{
return new ????(); // so, what type is TTree? how do we pass ctor parameters?
}
}
That can't work! This is where the enum type kicks in, when the type of the factory's product is unknown at compile-time - now because each tree type might have different constructor arguments, abstracting them into their own type can simplify things:
public class TreeFactory : ITreeFactory
{
private readonly IDictionary<TreeType, Func<ITreeArgs,ITree>> _create;
public TreeFactory(IDictionary<TreeType, Func<ITreeArgs,ITree>> factoryMethods)
{
_create = factoryMethods;
}
public ITree Create(TreeType treeType, ITreeArgs args)
{
return _create[treeType](args);
}
}
Where ITreeArgs
could perhaps encapsulate an object
that merely exposes an array of constructor arguments, whatever they are. Notice that the factory class itself doesn't even know/care how each TreeType
gets created - it receives a dictionary of factory methods (one for each TreeType
) and simply calls into it in the Create
method; this means if you want to modify how this factory class generates such or such ITree
implementation, you don't even need to change the factory class's code!
This is probably overkill for your example code however, since all your ITree
implementations seem to have a default constructor, therefore the generic factory would work.