gpt4 book ai didi

c# - .NET 重构,DRY。双重继承、数据访问和关注点分离

转载 作者:太空狗 更新时间:2023-10-29 23:18:54 27 4
gpt4 key购买 nike

背景故事:

因此,在过去的几个晚上里,我一直在研究架构问题,一直在尝试重构。没什么重要的,但它一直困扰着我。这实际上是 DRY 中的一个练习,并试图将其发挥到极致,因为 DAL 架构完全 DRY。这是一个完全哲学/理论的练习。

该代码部分基于 @JohnMacIntyre 之一我最近说服他在 http://whileicompile.wordpress.com/2010/08/24/my-clean-code-experience-no-1/ 上写博客的重构。 .我稍微修改了代码,就像我倾向于的那样,以便将代码更进一步——通常,只是为了看看我能从一个概念中得到什么额外的里程……无论如何,我的理由在很大程度上是无关紧要的。

我的部分数据访问层基于以下架构:

abstract public class AppCommandBase : IDisposable { }

这包含基本内容,例如命令对象的创建和 AppCommand 处理后的清理。我所有的命令基础对象都源自于此。

abstract public class ReadCommandBase<T, ResultT> : AppCommandBase

这包含影响所有读取命令的基本内容 - 特别是在这种情况下,从表和 View 中读取数据。无需编辑、无需更新、无需保存。

abstract public class ReadItemCommandBase<T, FilterT> : ReadCommandBase<T, T> { }

这包含一些更基本的通用内容——比如从数据库中的表中读取单个项目所需的方法定义,其中表名、关键字段名和字段列表名被定义为必需的抽象属性(由派生类定义。

public class MyTableReadItemCommand : ReadItemCommandBase<MyTableClass, Int?> { }

这包含定义我的表名的特定属性、表或 View 中的字段列表、关键字段的名称、将数据从 IDataReader 行解析到我的业务对象的方法以及启动的方法整个过程。

现在,我的 ReadList 也有这个结构......

abstract public ReadListCommandBase<T> : ReadCommandBase<T, IEnumerable<T>> { }
public class MyTableReadListCommand : ReadListCommandBase<MyTableClass> { }

区别在于 List 类包含与列表生成相关的属性(即 PageStart、PageSize、Sort 并返回一个 IEnumerable)与返回单个 DataObject(只需要一个过滤器来标识唯一记录)。

问题:

我讨厌我的 MyTableReadListCommand 类中有一堆属性,这些属性在我的 MyTableReadItemCommand 类中是相同的。我考虑过将它们移动到辅助类,但虽然这可能会将成员内容集中在一个地方,但我仍然会在每个类中拥有相同的成员,而是指向我仍然不喜欢的辅助类。

我的第一个想法是双重继承会很好地解决这个问题,尽管我同意双重继承通常是一种代码味道——但它会非常优雅地解决这个问题。那么,鉴于 .NET 不支持双重继承,我该何去何从?

也许不同的重构会更合适......但我无法思考如何回避这个问题。

如果有人需要完整的代码库来了解我在喋喋不休的内容,我的 DropBox 上有一个原型(prototype)解决方案 http://dl.dropbox.com/u/3029830/Prototypes/Prototype%20-%20DAL%20Refactor.zip .有问题的代码在 DataAccessLayer 项目中。

附言这不是正在进行的事件项目的一部分,它更像是我自己娱乐的重构难题。

在此先感谢大家,我很感激。

最佳答案

将结果处理与数据检索分开。您的继承层次结构在 ReadCommandBase 中已经足够深了。

定义一个接口(interface)IDatabaseResultParser。实现 ItemDatabaseResultParser 和 ListDatabaseResultParser,它们都带有 ReadCommandBase 类型的构造函数参数(也可能将其转换为接口(interface))。

当您调用 IDatabaseResultParser.Value() 时,它会执行命令、解析结果并返回 T 类型的结果。

您的命令专注于从数据库中检索数据并将它们作为某种描述的元组返回(实际元组或数组数组等),您的解析器专注于将元组转换为您需要的任何类型的对象。请参阅 NHibernates IResultTransformer 以了解其工作原理(它的名称可能也比 IDatabaseResultParser 更好)。

比继承更喜欢组合。

看过示例后,我会走得更远...

  1. 丢弃 AppCommandBase - 它不会为您的继承层次结构增加任何值(value),因为它所做的只是检查连接是否为空并打开并创建命令。
  2. 将查询构建与查询执行和结果解析分开 - 现在您可以大大简化查询执行实现,因为它要么是返回元组枚举的读取操作,要么是返回受影响行数的写入操作。
  3. 您的查询构建器可以全部封装在一个类中以包括分页/排序/过滤,但是围绕这些构建某种形式的有限结构可能更容易,这样您就可以将分页、排序和过滤分开。如果我这样做,我就不会费心构建查询,我会简单地将 sql 写在一个允许我传入一些参数的对象中(c# 中的有效存储过程)。

现在你有了 IDatabaseQuery/IDatabaseCommand/IResultTransformer 并且几乎没有继承 =)

关于c# - .NET 重构,DRY。双重继承、数据访问和关注点分离,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3580872/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com