我在使用Ioc和泛型时遇到了一些麻烦,特别是我的公司如何设置与此相关的层。我们正在MVP架构下工作。
我有一个汽车课:
class Car : ICar
{
IList<IWheel> wheels{get;set;}
IEngine engine{get;set;}
string registrationplate {get;set;}
public Car(){}
}
我希望能够获得一个新创建的ICar,我也希望能够通过Id找到一个ICar。问题是我不确定为什么在我正在研究的项目中做出了一些设计选择。已创建的其他服务的结构如下:
我有汽车和轮椅服务:
class WheelService : BaseService
{
IWheel wheel;
public IWheel Create()
{
return new wheel()
}
}
class CarService : BaseService
{
WheelService wheelservice;
public ICar CarCreate()
{
wheelservice = new Wheelservice()
car = new Car();
IWheel wheel = wheelservice.Create();
car.wheels.add(wheel);
return car;
}
public ICar Find(int id)
{
return (Car)base.Find<Car>(id);
}
}
首先,我发现'为每个实体提供服务'是奇怪的。我不会想到弱实体会有服务。我的想法是,CarService创建方法将像工厂方法一样,而不必调用轮子服务 此外,wheel服务创建方法实际上在演示者代码中用于将IWheel一直返回到UI,以便可以设置值并将其传回。再次,这对我来说似乎很奇怪。表示演示者可以从UI请求完整的ICar对象。
Service create方法中的依赖项是否正常?我原以为这会通过IoC引入。但是,如果ICar Create方法是处理所有创建(包括轮子等),那么容器可能会包含许多与此特定服务相关的接口?
如果我要引入接口,我需要调整当前使用具体类的CarService.Find方法。它使用BaseService,它只是这个层与容器交互以获得正确的存储库:
class BaseService
{
private object myRepository;
protected T GetRepository<T>(Type serviceType)
{
if (myRepository == null)
{
myRepository = (T)IoCRepositoryFactory.GetRepositoryInstance(typeof(T), serviceType);
}
return (T)myRepository;
}
protected virtual IGenericRepository Repository
{
get
{
return GetRepository<IGenericRepository>(this.GetType());
}
}
protected virtual T Find<T>(Object id) where T : class
{
return (T)Repository.GetByID<T>(id);
}
}
如果我只使用接口,我不确定如何调用此find方法,因为当前服务定义使用的是具体类。
抱歉这是一个冗长的帖子。我已经看了三天了,但是我需要知道其他人对当前设置的看法,以及我是否应该在服务层中使用IOC作为域对象,或者我是否应该遵循当前的设置。现在感觉有点让我觉得有点不适。
答案 0 :(得分:0)
我认为你有很多误解。
我将从服务结构开始。您不必让每个服务只处理一种类型的实体,但只要它不妨碍效率,就没有任何问题。您的示例可能过于简单,因此您可能可以让CarService处理Wheel管理而不会出现任何未来的维护问题,但通常按实体划分服务并且通常需要一些例外,它通常可以正常工作。
你写的IoC代码虽然有各种各样的错误。 IoC的目标是将所有将进行依赖关系管理的代码保存在一个有点偏僻的地方。您的代码具有CarService显式实例化WheelService,而应该由您的IoC容器处理。此外,使用GetRepository方法非常笨拙,也应该由IoC容器自动处理。
您可以设置服务和存储库的一种方法是这样的(如果您正在使用构造函数注入)。这只是一个例子(并且是一个冗长的例子),如果不完全理解它,不要将这个结构复制到你自己的代码中。
public interface IRepository {
//Some interfaces
//This method could only really be implemented if you are using an ORMapper like NHibernate
public T FindById<T>(Object id) { }
}
public class BaseRepository : IRepository {
//Some base crud methods and stuff. You can implement this if you're using an ORMapper
public T FindById<T>(Object id)
{
return CurrentSession.FindById<T>(id);
}
}
public class WheelRepository : BaseRepository {
//Wheel crud
//If you don't have an ORMapper because you're a masochist you can implement this here
public Wheel FindById(Object id) { }
}
public class CarRepository : BaseRepository {
//Car crud
//If you don't have an ORMapper because you're a masochist you can implement this here
public Car FindById(Object id) { }
}
public class BaseService {
protected BaseRepository _baseRepository;
//This constructor is automatically called by your IoC container when you want a BaseService
public BaseService(BaseRepository repository)
{
_baseRepository = repository;
}
//More methods
}
public class WheelService : BaseService
{
protected WheelRepository _wheelRepository;
public WheelService(WheelRepository wheelRepo) : base(wheelRepo)
}
public class CarService : BaseService
{
protected WheelService _wheelService;
protected CarRepository _carRepository;
public CarService(WheelService wheelService, CarRepository carRepository)
{
_wheelService = wheelService;
_carRepository = carRepository;
}
}
由于你正在使用MVP,我假设某种WPF / Winforms应用程序,虽然我想你也可以做一个web应用程序,如果你真的想让它适合asp.net。在任何一种情况下,它们都有一个工厂,您可以配置它来创建演示者类。在那个工厂里,你可以在那里进行所有的注射,在一个你永远不必担心的地方,甚至在设置之后再看一下。该代码只是称之为:
//Override the default factory method (just made this up)
public override Presenter GetPresenter(Type presenterType)
{
return ComponentFactory.GetInstance(presenterType);
}
然后,如果你有一个依赖于服务的演示者,那么它将自动存在,服务需求的所有东西也都存在。注意在其他地方没有丑陋的服务构造函数或工厂调用。所有依赖项都由容器自动设置。
我不知道为什么贵公司的代码会有那些糟糕的GetRepository方法。这是反模式的一个实例,因为你正在用一个GetRepository调用替换通常是新的Repository()的构造函数调用,而只是稍微更易于维护。
你应该尝试使用一些众所周知的容器。 Structuremap非常好。