问题
After listening to the Clean Code Talks, I came to understand that we should use factories to compose objects. So, for example, if a House
has a Door
and a Door
has a DoorKnob
, in HouseFactory
we create a new DoorKnob
and pass it to the constructor of Door
, and then pass that new Door
object to the constructor of House
.
But what about the class that uses the House
(say the class name is ABC
)? It will depend on the HouseFactory
, right? So do we pass the HouseFactory
in the constructor of ABC
? Won't we have to pass a whole lot of factories in the constructor that way?
回答1:
Staying with the Door and DoorKnob example, you don't inject a factory - you inject the DooKnob itself:
public class Door
{
private readonly DoorKnob doorKnob;
public Door(DoorKnob doorKnob)
{
if (doorKnob == null)
throw new ArgumentNullException("doorKnob");
this.doorKnob = doorKnob;
}
}
No factories are in sight in this level.
House, on the other hand, depends on Door, but not on DoorKnob:
public class House
{
private readonly Door door;
public House(Door door)
{
if (door == null)
throw new ArgumentNullException("door");
this.door = door;
}
}
This keeps options open until at last you have to compose everything in the application's Composition Root:
var house = new House(new Door(new DoorKnob()));
You can use a DI Container to compose at this level, but you don't have to. No factories are involved.
回答2:
If you inject too many factories that is a code smell called constructor over-injection that indicates your class is doing too much.
Many containers provide a feature called auto-factories. That means they generate factories of type Func<T>
automatically if they know how to generate T
.
Castle Windsor has an advanced feature called Typed Factory facilities which generates implementations of a factory interface on-the-fly.
There is also a port of typed factories for Unity in the TecX project.
回答3:
If you end up using Unity, I have recently implemented an equivalent of Castle Windsor Typed Factories for Unity. You can find the project at https://github.com/PombeirP/Unity.TypedFactories, and the NuGet package at http://nuget.org/packages/Unity.TypedFactories.
The usage is the following:
unityContainer
.RegisterTypedFactory<IFooFactory>()
.ForConcreteType<Foo>();
You just have to create the IFooFactory interface with a method returning IFoo, and the rest is done for you by the library. You can resolve IFooFactory and use it to create IFoo objects straight away.
来源:https://stackoverflow.com/questions/8980434/constructor-injection-do-we-inject-factories-as-well