C# 解析调用链反模式
在我的ASP.NET开发中,我开始注意到一些反模式的东西。它困扰着我,因为它让我觉得保持良好的设计是正确的,但同时它闻起来是错误的 问题在于:我们有一个多层应用程序,底层是一个类,处理对为我们提供数据的服务的调用。上面是一层类,可以转换、操作和检查数据。上面是ASP.NET页面 在许多情况下,来自服务层的方法在进入视图之前不需要任何更改,因此模型只是一个简单的过程,如:C# 解析调用链反模式,c#,asp.net,anti-patterns,C#,Asp.net,Anti Patterns,在我的ASP.NET开发中,我开始注意到一些反模式的东西。它困扰着我,因为它让我觉得保持良好的设计是正确的,但同时它闻起来是错误的 问题在于:我们有一个多层应用程序,底层是一个类,处理对为我们提供数据的服务的调用。上面是一层类,可以转换、操作和检查数据。上面是ASP.NET页面 在许多情况下,来自服务层的方法在进入视图之前不需要任何更改,因此模型只是一个简单的过程,如: public List<IData> GetData(int id, string filter, bool ch
public List<IData> GetData(int id, string filter, bool check)
{
return DataService.GetData(id, filter, check);
}
public List GetData(int-id、字符串过滤器、bool检查)
{
返回DataService.GetData(id、filter、check);
}
这并没有错,也不一定很糟糕,但它创建了一种奇怪的复制/粘贴依赖关系。我也在研究底层服务,它也大量复制了这种模式,并且始终有接口。所以发生的事情是,“我需要将intsomeotherid
添加到GetData
”,所以我将它添加到模型、服务调用方、服务本身和接口中。实际上,GetData
代表了几种方法,它们都使用相同的签名,但返回不同的信息。界面对这种重复有点帮助,但仍然会在这里和那里出现
这个反模式有名字吗?是否存在修复,或者对架构进行重大更改是唯一真正的方法?听起来我需要展平我的对象模型,但有时数据层正在进行转换,以使其具有价值。我还喜欢将代码在“调用外部服务”和“提供页面数据”之间分开。听起来您需要另一个接口,因此该方法类似于:
public List<IData> GetData(IDataRequest request)
公共列表获取数据(IDataRequest请求)
我建议您使用来解决此问题。基本上,您的服务可以有如下签名:
IEnumerable<IData> GetData(IQuery<IData> query);
IEnumerable GetData(IQuery查询);
在IQuery接口内部,如果您使用的是诸如NHibernate之类的ORM并返回IData对象列表,则可以有一个将工作单元作为输入的方法,例如事务上下文或类似ISession的内容
public interface IQuery<T>
{
IEnumerable<T> DoQuery(IUnitOfWork unitOfWork);
}
公共接口iquiry
{
IEnumerable DoQuery(IUnitOfWork unitOfWork);
}
通过这种方式,您可以创建符合您的需求的强类型查询对象,并为您的服务提供一个干净的接口。《来自Ayende》对这个主题有很好的解读。你是在把权力下放给另一层,这不一定是一件坏事 您可以在这里或在下面的另一个方法中添加一些其他逻辑,这些逻辑只属于此层,或者替换为使用另一个实现将该层委托给其他层,因此它当然可以很好地使用所讨论的层
您可能有太多的层,但我不会仅从看到这一层就这么说,更多的是从没有看到任何其他层就这么说。从您所描述的内容来看,听起来您在应用程序中遇到了抽象的“权衡”之一 考虑这样一种情况,即这些“调用链”不再“传递”数据,而是需要一些转换。现在可能不需要这样做,当然也可以这样做
然而,在这种情况下,能够轻松地在层与层之间引入数据更改的积极副作用似乎并没有太多的技术债务需要处理。我也使用这种模式。但是,我使用它是为了将域模型对象与数据对象解耦 在我的例子中,我没有像示例中那样“穿过”来自数据层的对象,而是将其“映射”到位于域层中的另一个对象。我过去习惯于用手去做这件事 在大多数情况下,我的域对象看起来与它起源的数据对象完全相同。然而,有时我需要展平来自数据对象的信息。。。或者我可能对数据对象中的所有内容都不感兴趣。。我将数据对象映射到一个定制的域对象,该域对象只包含我的域层感兴趣的字段 此外,这还有一个副作用,即当我决定为其他内容重新考虑或更改数据层时,它不必影响我的域对象,因为它们是使用映射技术解耦的 下面是对auto mapper的描述,我认为这是该设计模式试图实现的目标: AutoMapper面向模型投影场景,将复杂对象模型展平到DTO和其他简单对象,这些对象的设计更适合于序列化、通信、消息传递,或者只是域和应用程序层之间的反损坏层
事实上,你选择的方式,是拥有你所拥有的东西的原因(我并不是说它不好) 首先,让我说你的方法很正常 现在,让我想想你的图层:
- 您的服务-提供某种类型的强类型访问模型。这意味着它有一些类型的参数,在一些特殊类型的方法中使用它们,这些方法返回一些特殊类型的结果
- 您的服务访问层也提供了相同的模型。因此它为特殊类型的方法获取特殊类型的参数,返回特殊类型的结果
- 等等
UserEntity
对象
现在是另一种方法:
还记得SqlDataReader
是如何工作的吗?不是很强的类型,对吗?
在我看来,你在这里打电话是因为你错过了一些不强壮的人
public UserEntity GetUserByID(int userEntityID);
public Entity SelectByID(IEntityID id);
public Entity SelectAll();
IData GetData(IQuery<IData> query)
IQuery<IData> BindRequest(IHttpRequest request)