我一直在使用IoC容器已经很长一段时间但是今天我发现一些“模式”一遍又一遍地出现在代码中。为了给你一些背景知识,我现在正致力于主要用于数据分析的Web应用程序。那里有一系列功能,要求用户在一开始就选择我们称之为QueryTypeContex
的功能。选择此查询类型后,可能会采取其他步骤,但所有步骤都在此特定QueryTypeContex
中执行。在gui中,QueryTypeContex
提货被表示为打开包含其他控件的新标签。
当用户使用给定QueryTypeContex
时,对服务器的所有ajax调用都包含QueryTypeId
,用于标识用户选择并用于在服务器上构建QueryTypeContex
,然后用于各种数据检索和操纵。
我发现我们使用Ioc容器构建的许多控制器(我们使用asp.net mvc)有一个共同点。有一种看起来像这样的动作方法:
public class AttributeController : Controller
{
public AttributeController(IUsefulService usefulService)
{
_usefulservice = usefulService;
}
ActionResult GetAttributes(QueryTypeContex context)
{
var dataDto = _usefulService.Manipulate(context, currentUser);
return JSon(dataDto);
}
...
}
为了将QueryTypeContex
绑定到action参数,我们使用自定义模型绑定器从数据库中提取一些信息。一旦服务获得QueryTypeContex
作为参数,它就将它或其属性传递给方法参数中的协作者,例如数据访问层。所以有一个看起来像这样的工厂类
public interface IDateValueFactory
{
DateValue CurrentYear(QueryTypeContex context);
DateValue RollingMonth(int numberOfMonths, QueryTypeContex context);
DateValue RollingQuareter(int numberOfQuarters, QueryTypeContex context);
}
public class DateValueFactory : IDateValueFactory
{
public DateValueFactory(IDateValueDb dateValueDb)
{
_dateValueDb = dateValueDb;
}
public DateValue CurrentYear(QueryTypeContext context)
{
var currentYear = _dateValueDb.GetCurrentYear(context.Id);
return new DateValue(DateValueType.CurrentYear, currentYear, context);
}
public DateValue RollingMonth(int numberOfMonths, QueryTypeContex context)
{
return new DateValue(DateValueType.RollingMonth, numberOfMonths, context);
}
...
}
如您所见,所有这些方法都将QueryTypeContex
作为参数更为重要他们在短暂的生命中获得QueryTypeContex
的相同实例(一个网络请求) 。所以我开始怀疑我是否可以重构这一点,以便每当许多服务类方法需要QueryTypeContex
作为参数时,它将通过构造函数注入,而不是重复传递相同的值。例如:
public interface IDateValueFactory
{
DateValue CurrentYear();
DateValue RollingMonth(int numberOfMonths);
DateValue RollingQuareter(int numberOfQuarters);
}
public class DateValueFactory : IDateValueFactory
{
public DateValueFactory(IDateValueDb dateValueDb, QueryTypeContext context)
{
_dateValueDb = dateValueDb;
_context = context;
}
public DateValue CurrentYear()
{
var currentYear = _dateValueDb.GetCurrentYear(_context.Id);
return new DateValue(DateValueType.CurrentYear, currentYear, _context);
}
public DateValue RollingMonth(int numberOfMonths)
{
return new DateValue(DateValueType.RollingMonth, numberOfMonths, _context);
}
...
}
现在真正的问题是: 对于这类事情这是一个好主意还是违反了我应该坚持的一些设计原则?
为了注入QueryTypeContex
实例,使用来自http请求的信息进行构建我考虑将QueryTypeId嵌入到uris中,以便它可以在服务器上的RouteData中使用。然后在构造控制器之前,我可以将其拉出来,构建QueryTypeContex
,为该请求创建嵌套的IoC容器并将其注入容器中。然后,只要某个类需要QueryTypeContex
来执行它的工作,它就会简单地将它声明为构造函数参数。
答案 0 :(得分:5)
你可以将任何有意义地推送到构造函数的东西作为依赖。与构造函数注入相关的依赖关系是实现细节,而方法参数是模型的API 的一部分。
重构通过构造函数连接的依赖关系比更改API要容易得多,因此出于可维护性的原因,您应该选择尽可能少的方法参数。