我们目前的代码看起来如下所示,工厂被注入很多类,然后调用工厂获取他们想要的实例。
public class Service
{
public Service(IFactory factory)
{
_car = factory.GetCar<Entity>();
}
}
public class Car : ICar
{
}
public interface IFactory
{
ICar<TEntity> GetCar<TEntity>();
IBoat<TEntity> GetBoat<TEntity>();
}
public class Factory : IFactory
{
ConnectionDetails _connectionDetails;
public Factory(ConnectionDetails connectionDetails)
{
_connectionDetails = connectionDetails;
}
TEntity GetCar<TEntity>()
{
var car = new Car<TEntity>(_connectionDetails);
car.Initialize();
return car;
}
}
我希望能够创建一个解决方案,允许直接在Car<TEntity>
上请求依赖,而无需先通过工厂。
以下是安装单个TEntity
的示例,但我如何将其设置为通用?
我尝试过使用开放式泛型,但我无法看到如何从.UsingFactoryMethod()
中获取正确的返回类型。
我知道我可以从RequestedType
中获取CreationContext
,但我不知道如何使用它来解决此问题。
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<ICar<TEntity>>().UsingFactoryMethod(
kernel =>
{
var factory = kernel.Resolve<IFactory>();
return factory.GetCar<TEntity>();
}));
}
}
答案 0 :(得分:1)
我个人发现混合了依赖注入的工厂可能有点反模式,因为它隐藏了除了对象图根之外的其他地方的实现/创建细节。此外,当混合这两者时,不清楚谁最终有责任创建和维护对象及其生命周期。
我建议你转而允许容器根据公共基本接口/类完全处理创建细节。
void Main()
{
var container = new WindsorContainer();
container.Install(new Installer());
var car = container.Resolve<Car>();
car.Dump();
}
public class Service
{
private ICar<CarEntity> _car;
public Service(ICar<CarEntity> car)
{
_car = car;
}
}
public class TEntity { }
public class CarEntity : TEntity { }
public class BoatEntity : TEntity { }
public interface ICreatable { }
public interface ICar<TEntity> : ICreatable { }
public class Car : ICar<TEntity>
{
private ConnectionDetails _connectionDetails;
public Car(ConnectionDetails connectionDetails)
{
_connectionDetails = connectionDetails;
Initialize();
}
public void Initialize() {}
}
public class ConnectionDetails { }
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<ConnectionDetails>()
.ImplementedBy<ConnectionDetails>());
container.Register(
Classes.FromAssemblyInThisApplication()
.BasedOn(typeof(ICreatable))
.WithServiceAllInterfaces()
.WithServiceSelf()
.LifestyleTransient());
}
}
答案 1 :(得分:1)
你可以使用Castle的Typed Factory Facility来实现这一目标。
首先,您需要创建Castle将实现的接口:
public interface IFactory
{
ICar<TEntity> CreateCar<TEntity>(ConnectionDetails connectionDetails);
IBoat<TEntity> CreateBoat<TEntity>(ConnectionDetails connectionDetails);
void Release(object component); // left type as object so it can release either a boat or a car
}
使用此实现,只要您的对象在封闭泛型类型的容器中注册为其服务名称,castle就会自动找到正确的对象。
然后您只需添加设施并注册工厂界面:
kernel.AddFacility<TypedFactoryFacility>();
kernel.Register(Component.For<IFactory>().AsFactory());
我在顶部链接的文章也涵盖了界面中方法的命名语义,因为某些词具有特殊含义。