- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在向我们的网站添加功能,该功能使用 MSMQ 异步执行长时间运行的进程。但是,执行此异步操作意味着我们需要在用户的请求完成时通知他们。使用命令模式,我创建了一个名为 INotify 的接口(interface)*,并将其组合到消息类中,因此消息处理类可以简单地在消息的 INotify 对象上调用 GiveNotice()。第一个实现 EmailNotify 比预期的要困难得多,因为我惊讶地发现 MailMessage 不可序列化,但它成功了。
现在我正在开发一个新的具体通知程序 DBNotify,它将调用某种 SP 并更新主事务数据库中的状态。我被绊倒了,因为我想重用我们已经创建的 DAL 架构,但 INotify 是 Model 项目的成员,它比 DAL 更基础。
我们的层次结构如下所示:通用 > 型号 > DAL > BAL
这里是关于等级的更多详细信息。请记住,我继承自:Common 负责应用程序中许多地方使用的所有“实用程序”功能,例如访问配置设置、解析字符串、非业务相关功能。
模型是业务对象,一些人称之为数据传输对象,getter 和 setter 的集合。我在这一层添加了一些“智能”,但只有该对象内部的业务规则,例如“项目的名称必须以字母数字字符开头。”
DAL 是数据访问层,理论上,这里发生的只是将模型对象移入和移出数据库。
BAL是业务层;从理论上讲,管理对象交互的业务规则是强制执行的(即“一个表单必须至少有两个项目。”)。
因此 INotify 接口(interface)被定义为一个抽象,以允许通知方法独立变化(即电子邮件、TXT、twitter 等)。它是系统的基础,因此我在独立于 DAL 层的模型层创建了它。但是,我正在创建 INotify 的新具体实现,其通知方法是调用数据库中的 SP。
有没有其他人处理过以与数据库交互为目的的业务对象,您如何将其放置在您的 N 层架构中?
在你告诉我使用 Linq to Sql 之前,非常感谢。这不是一个技术问题(我该怎么做),而是一个设计问题(我应该怎么做)。
我认为有一个 StackExchange 网站更专注于这类与语言无关的设计问题,所以我将把它复制到那里。
最佳答案
也许不是您问题的真正答案,但仍然值得思考。
我不同意您将数据访问放在组件层次结构中的什么位置。我不会将它放在两个功能域层之间。甚至不在单域模型类的“之上”。数据访问或持久性不是任何域类的关注点。应该只是能对他们做的事,而不是他们做的事。
即使我开始编写诸如 TClient.Save
和 TClient.Load
之类的代码,但我现在得出的结论是,决定它需要的不是客户端被保存,但用户交互决定何时需要域实例的数据,因此应该加载,以及何时应该保留客户端的数据,如果有的话。因此,我现在支持编码(在 GUI 中,更具体地说是 GUI 中的 Controller ),例如 DataStore.Load(ClientInstance)
和 DataStore.Save(ClientInstance)
.然后由数据访问层决定如何做到这一点。它可以使用 C# 中的反射或 Delphi 中的新 RTTI 来迭代所有客户端的属性,以便将它们发送到数据库。
虽然分层是一个很好的概念,可以通过简单地坚持“你可以向下调用但不能向上调用”来分离关注点并防止你把东西到处乱放,但它在处理日志记录、异常等问题时并没有多大帮助处理、通知和所有其他组件/层需要的所有其他有趣的横切关注点。
此外,公共(public)层,因为它是一个实用层,所以所有其他层都应该可以访问。
将其全部放在一张图片中(我保留了您在简单域类、您的模型和跨类业务规则、您的 BAL 之间所做的区分):
+---+ +-------------+
| C |<--| Data Access |<--------------------------+
| o | +-------------+ |
| m | | |
| m | | |
| o | v |
| n | +-------------+ +----------------+ +-----+
| |<--| Model +<--| Cross class |<--| GUI |
| | +-------------+ | business rules | | |
| | | | | |
| |<--------------------| | | |
| | +----------------+ | |
| | | |
| |<-----------------------------------------| |
+---+ +-----+
调用数据库的 INotify 实现目前在模型中,在上图中,它本身不调用数据访问层,它仅被数据访问层调用,或者更确切地说,被数据访问层询问。
真正的问题是 INotify 是否应该在“模型”中,域层的一部分,或者它是否应该是一个通用接口(interface)并且应该有一个单独的“通知”层/组件可以从域访问和图形用户界面。这个新组件不仅可以关注通知本身,还可以关注许多其他横切关注点,例如日志记录。它至少可以以某种回调方式访问公共(public)(当然)和数据访问组件以及 GUI。
在下图中,我尝试将其可视化,但我不太擅长可视化,并且总是遇到那些讨厌的横切机问题。这就是为什么没有从领域层到横切关注点的调用箭头,尽管领域层当然应该能够访问例如“Logger”接口(interface)。也许我正在努力区分通用组件和横切组件,并且可以提出将它们放在一起的论点,并将它们可视化为“实用程序”层/组件中的单独 block 。
+--------------------------------------------+
+-----| Cross cutting concerns |
| +--------------------------------------------+
v v^ ^
+---+ +-------------+ |
| C |<--| Data Access |<--------------------------+ |
| o | +-------------+ | |
| m | | | |
| m | | | |
| o | v | v
| n | +-------------+ +----------------+ +-----+
| |<--| Model +<--| Cross class |<--| GUI |
| | +-------------+ | business rules | | |
| | | | | |
| |<--------------------| | | |
| | +----------------+ | |
| | | |
| |<-----------------------------------------| |
+---+ +-----+
关于c# - 在 N 层架构中实现数据库功能对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5489440/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!