gpt4 book ai didi

.net - 现实生活与SOLID开发一起工作

转载 作者:行者123 更新时间:2023-12-04 16:44:37 25 4
gpt4 key购买 nike

我最近学习了SOLID开发,现在我面临着一些挑战,那就是什么时候是好的习惯,什么时候不是。

例如,我开发了一个包含成员的网站。我构建了一个Authentication Business Logic类,该类应确定身份验证方案,这些方案是:


登录用户
获取登录用户
注册用户
恢复用户密码


此类具有4个依赖项:


数据库/服务
HttpContext(用于用户状态)
ValidationRules(一些其他业务逻辑规则,以便登录用户)
SMTP-用于发送


现在,由于未使用依赖项注入,因此感觉有些代码有异味。

我不确定的一些问题:


我可以直接将SMTP依赖项注入到“还原密码和注册”方法中,因为所有其他方法均与此无关。我是不是该?
某些方法(例如注销)没有使用数据库,为什么当我知道不需要使用数据库依赖项时为什么要启动数据库依赖项。
这是针对我的一些业务逻辑。在我的控制器中,这个问题要大得多,因为我需要加载的负载超过一个BL,并且我的所有业务类都具有相同的难闻气味。


我觉得我做错了,请帮忙!

最佳答案

认证业务逻辑类,应确定
身份验证方案,包括:登录用户,获取登录用户,
注册用户,找回用户密码。


您的身份验证业务逻辑类已经违反了Single Responsibility Principle。尽管您可能认为该类的唯一职责是“身份验证”,但这几乎不能称为一种职责,因为您可以实现数百个用于身份验证的用例,从而导致一个丑陋的大屁股类。那个班级还会负有责任吗?而是,为每个类实现一个用例。在这种情况下,您的课程将具有非常明确和狭窄的职责。


HttpContext(用于用户状态)


您的业​​务逻辑应该对所使用的技术一无所知(当然,除了它是.NET之外,我们不能真正抽象出.NET),因此它不应依赖于HttpContext。取决于HttpContext违反了Dependency Inversion Principle(DIP)和Interface Segregation Principle(ISP)。

DIP说:“高级模块应该……取决于抽象。”您的业​​务层是“较高级别的模块”,但它不依赖于抽象,而是依赖于较低级别的模块(HttpContext)。这将业务层类与实际的Web逻辑紧密结合在一起。

此外,即使您使用System.Web.HttpContextBase抽象,您仍将依赖于由较低层模块定义的抽象,而根据DIP,“抽象归上层/策略层所有”。其背后的想法是,您不希望您的代码对较低的层有强烈的依赖性​​,因为这会使较高层的层更依赖于此,并且除此以外,较低层的层无法定义以下抽象:为您的应用程序正确。接下来表达这个问题。

ISP指出“不应强迫任何客户端依赖其不使用的方法”。换句话说,抽象应该针对客户的特殊需求而定制,并且应该狭窄。 “这些缩小的接口也称为角色接口”。 HttpContextHttpContextBase都违反了ISP,因为它们很宽并且可以用于一般用途。它们是一个大问题,其中一切都是字符串。这使您的代码可以使用非常广泛的API,这使该API难以使用。这也阻碍了可测试性,因为不可能伪造HttpContext,甚至抽象的HttpContextBase都不容易伪造。如果您使用ISP,则您的生产代码和测试代码都将变得更加干净。这也阻碍了应用程序的可重用性,因为您可能希望稍后在没有Web请求概念的后台进程中运行业务逻辑的某些部分。而且它妨碍了灵活性,因为您可能想一次拦截或修饰在该HttpContext上执行的某些操作。例如,您可能想在HttpContext请求用户详细信息时记录日志。但是,当您的代码直接依赖于HttpContext时,这意味着您被迫在整个代码库中进行全面更改。必须在整个代码中进行大范围更改,这表明您违反了Open/Closed Principle

而是在BL中定义您自己的IUserContext抽象,并在您的Web应用程序中创建一个AspNetUserContext实现(实现IUserContext)。请注意,您不应该定义IHttpContext抽象,因为它仍然会违反SRP和ISP,并且基本上是泄漏抽象(泄漏抽象是DIP违规),因为业务层不必了解网络请求的存在。


我可以直接注入SMTP依赖项


这样做时,您将再次违反Dependency Inversion Principle。您的业​​务层不依赖于抽象,而是依赖于较低级别的模块(您的SMTP类)。这将业务层类与实际的SMTP逻辑紧密结合在一起。相反,您应该为此定义自己的抽象,例如IMailSender

这听起来可能很奇怪,您可能会觉得您永远都不会更改邮件的发送方式,因为电子邮件是唯一的方式。但是,即使电子邮件已经存在了很多年,您仍可能希望更改电子邮件的处理方式,因为在当前的实现中,电子邮件不会随业务交易自动发送。这意味着您可能已将邮件推送到SMTP服务器(无法回滚的操作),但是此后总操作仍然可能失败。如果失败,则意味着回滚打开的数据库事务,但此时仍将发送邮件。您无法将其回叫,最终将在以后再次发送该邮件。这将使您的接收者感到烦恼,甚至可能使您发送事务回滚后不再存在的信息(例如包含数据库ID的url)。

为了减轻这种情况,您将必须将邮件写入事务性队列(例如,带有应发送邮件的数据库表)。此操作应在与业务逻辑运行相同的事务中运行。这意味着您可以在同一事务中对多个消息进行排队,并且当操作失败时,它们都会全部回滚。操作成功后,所有消息将变为可用,并且某些其他(后台)进程可以将其提取并发送。

这只是一种可能的方式。邮件的发送方式将来可能会更改,但是如果没有IMailSender抽象,则将很难解决。


某些方法(例如注销)没有使用数据库,为什么我应该
当我知道不需要使用它时,请启动db依赖项。


通常,当不总是使用依赖项时,这不是问题,因为创建对象图(具有所有直接和间接依赖项的服务)should be very fast。但是在您的情况下,您所看到的是您的方法不够紧密。这表明违反了单一责任。相反,您应该为Logout操作提供自己的类。由于此操作不需要数据库,因此这里不需要数据库依赖项。


在我的控制器中,这个问题要大得多,因为我需要加载更多
那么一个BL和我所有的商务舱都有同样的难闻的气味。


您的控制器可能也违反了“单一责任原则”。 SRP违规的一个很好的指示是类具有的依赖项数量。启发式方法是4或5。具有5个以上的依赖项,您的类很可能承担太多职责。

当您遵循SOLID时,您将获得许多小型且专注的课程。乍看起来,这似乎需要大量工作和代码,但实际上,这会使系统更易于维护。如果您在为如何创建业务逻辑而苦苦挣扎,请查看this article

关于.net - 现实生活与SOLID开发一起工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19608208/

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