抽象视图:我想将信息从一个层传递到另一个层(注意:当这个帖子有更好的标题时,请告诉我)。
我有一个ViewModel,它与我的Views和我的Service层进行通信。 我与持久层进行了服务层通信。
我们假设我有以下类:
public class EmployeeViewModel()
{
// The following properties are binded to my View (bidirectional communication)
public Firstname ...
public Lastname ...
public Email ...
public void PerformingSearch()
{
...
EmployeeService.Search(...);
...
}
}
public class EmployeeService()
{
public List<Employee> Search(...)
{
// Searching in db
}
}
将数据从ViewModel移交给我的服务层(例如执行搜索)的最佳做法是什么?
我看到一些选项(ViewModel透视图):
这个问题有没有设计模式?怎么称呼?什么选择最好?我错过了什么吗?
答案 0 :(得分:4)
您的特定示例告诉我,您当前的体系结构包含一个服务层,该服务层可以充当数据访问层的代理。如果没有对您的架构有更深入的了解,我会建议尽可能与您的环境允许的keep it simple解决方案。
现在让我们尝试选择策略以获得可能的解决方案模型。 您的用户故事听起来像是:“用户提交信息以获取员工列表”。
您当前的用例已简化:
重构的用例示例:
看起来更容易吗?
简而言之CQS:
声明每个方法都应该是一个执行的命令 一个操作,或一个将数据返回给调用者的查询,但不是两者。
在您的特定情况下,我们需要关注queries,其中:
查询:返回结果,不要更改系统的可观察状态(没有副作用)。
但这对您有何帮助?让我们看看。 CQS查询端的非常详细的解释可以在Meanwhile... on the query side of my architecture的“Steven”博客文章中完整阅读。
定义查询对象的接口
public interface IQuery<TResult> {}
查询处理程序定义:
public interface IQueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
现在,这是“搜索”查询对象的实现。这实际上是“如何传递信息”问题的答案:
public class FindEmployeeBySearchTextQuery : IQuery<Employee>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
最后一个您将在查询对象中传递的查询处理程序:
public class FindEmployeeBySearchTextQueryHandler
: IQueryHandler<FindEmployeeBySearchTextQuery, List<Employee>>
{
private readonly IDbContext db;
public FindEmployeeBySearchTextQueryHandler(IDbContext db)
{
this.db = db;
}
public List<Employee> Handle(FindEmployeeBySearchTextQuery query)
{
return (
from employee in this.db.employees
where employee.FirstName.Contains(query.FirstName) ||
employee.LastName.Contains(query.LastName) ||
employee.Email == query.Email
select employee )
.ToList();
}
}
注意:此Handle()
示例实现使用实体框架“IDbContext
,您必须根据需要对其进行返工/修改(ADO.NET,NHibernate等)。
最后在你的视图模型中:
public class EmployeeViewModel()
{
private readonly IQueryHandler _queryHandler;
public EmployeeViewModel(IQueryHandler queryHandler)
{
_queryHandler = queryHandler;
}
public void PerformingSearch()
{
var query = new FindEmployeeBySearchTextQuery
{
FirstName = "John",
LastName = "Doe",
Email = "stack@has.been.over.flowed.com"
};
List<Employee> employees = _queryHandler.Handle(query);
// .. Do further processing of the obtained data
}
}
此示例假定您正在使用依赖注入 您将IQueryHandler实现注入到视图模型构造函数中,然后使用接收到的实现。
使用这种方法,您的代码变得更清晰,更多的用例驱动,并且可以更好地隔离责任,您可以通过进一步的跨领域问题轻松测试和装饰。