如何理解松散耦合应用程序中的大局?
我们一直在使用松耦合和依赖注入开发代码。
很多“服务”风格的类都有一个构造函数和一个实现接口的方法。 每个班级都很容易孤立地理解。
然而,由于耦合的松弛,查看课程不会告诉你关于它的类或它适合放大图的地方。
使用Eclipse跳转到协作者并不容易,因为您必须通过界面进行操作。 如果接口Runnable
,那就是在寻找哪一类是在实际插入没有帮助。真的有必要回到DI容器定义,并试图从那里理出头绪。
以下是来自依赖注入服务类的一行代码: -
// myExpiryCutoffDateService was injected,
Date cutoff = myExpiryCutoffDateService.get();
这里的耦合尽可能松散。 有效期限以任何方式实际执行。
以下是它在更多耦合应用程序中的样子。
ExpiryDateService = new ExpiryDateService();
Date cutoff = getCutoffDate( databaseConnection, paymentInstrument );
从紧密耦合的版本中,我可以推断,截止日期在某种程度上由使用数据库连接的支付工具确定。
我发现第一种风格的代码比第二种风格的代码难以理解。
你可能会争辩说,在阅读这门课时,我不需要知道截止日期是如何计算出来的。 确实如此,但是如果我正在缩小bug或确定增强功能需要插入的位置,那么这是非常有用的信息。
有没有人遇到过这个问题? 你有什么解决方案? 这只是一些适应? 是否有任何工具可以让班级连线的方式可视化? 我应该让课程更大还是更融合?
(由于我对任何答案感兴趣,故意将这个问题留在容器不可知的位置)。
尽管我不知道如何在单个段落中回答这个问题,但我试图在博客文章中回答它:http://blog.ploeh.dk/2012/02/02/LooseCouplingAndTheBigPicture.aspx
总而言之,我发现最重要的一点是:
一些工具知道DI框架并知道如何解决依赖关系,使您能够以自然的方式导航代码。 但是,如果无法使用,则只需使用IDE提供的所有功能即可。
我使用Visual Studio和一个定制的框架,所以你描述的问题是我的生活。 在Visual Studio中,SHIFT + F12是我的朋友。 它显示对光标下的符号的所有引用。 过了一段时间,你习惯于通过代码进行必要的非线性导航,并且根据“哪个类实现此接口”和“注入/配置站点在哪里”这一术语来考虑是第二性质,以便我可以看到哪个类正被用来满足这种接口依赖性“。
还有一些可用于VS的扩展,它们提供UI增强功能以帮助实现此目的,例如Productivity Power Tools。 例如,您可以将鼠标悬停在界面上,会弹出一个信息框,您可以单击“实施者”查看解决方案中实现该界面的所有类。 您可以双击跳转到任何这些类的定义。 (无论如何,我仍然通常只使用SHIFT + F12)。
我刚刚就此进行了内部讨论,最后写了这篇文章,我觉得这篇文章太好了,不愿意分享。 我几乎是在未经编辑的情况下复制它,但即使它是更大的内部讨论的一部分,我认为它大部分可以单独使用。
讨论的内容是介绍一个名为IPurchaseReceiptService
的自定义接口,以及是否应该使用IObserver<T>
替换它。
那么,我不能说我有关于这些的强大数据点 - 这只是我正在追求的一些理论......然而,我目前关于认知开销的理论是这样的:考虑你的特殊IPurchaseReceiptService
:
public interface IPurchaseReceiptService
{
void SendReceipt(string transactionId, string userGuid);
}
如果我们将它保留为它当前的标题接口,则它只有一个SendReceipt
方法。 这很酷。
没有那么酷的是,你必须为接口提供一个名称,并为该方法提供另一个名称。 两者之间有一些重叠:单词Receipt出现两次。 IME,有时候这种重叠可能会更加明显。
此外,接口的名称是IPurchaseReceiptService
,这也不是特别有用。 服务后缀实质上是新的管理器,而IMO是一种设计气味。
此外,您不仅需要命名该接口和方法,还必须在使用该变量时命名该变量:
public EvoNotifyController(
ICreditCardService creditCardService,
IPurchaseReceiptService purchaseReceiptService,
EvoCipher cipher
)
在这一点上,你基本上说过三次同样的事情。 根据我的理论,这是认知开销,以及设计可以并且应该更简单的气味。
现在,将其与使用像IObserver<T>
这样的着名界面进行对比:
public EvoNotifyController(
ICreditCardService creditCardService,
IObserver<TransactionInfo> purchaseReceiptService,
EvoCipher cipher
)
这可以让你摆脱官僚主义,减少设计的核心问题。 您仍然有意向 - 揭示命名 - 您只将设计从“类型名称角色提示”转换为“参数名称角色提示”。
当谈到关于“不连贯性”的讨论时,我毫不IObserver<T>
使用IObserver<T>
会神奇地使这个问题消失,但我对此有另一种理论。
我的理论是,许多程序员发现接口编程如此困难的原因正是因为他们习惯于Visual Studio的定义功能(顺便说一句,这是工具如何腐蚀头脑的又一例子)。 这些程序员永远处于一种心境,他们需要知道'界面的另一面'是什么。 为什么是这样? 难道是因为抽象很差?
这与RAP相关联,因为如果您确认程序员相信每个接口背后都有一个特定的实现,那么他们就认为接口只能这样,这就难怪了。
但是,如果您应用RAP,我希望程序员能够慢慢学会,在特定接口背后,可能会有该接口的任何实现,并且它们的客户端代码必须能够处理该接口的任何实现,而不会改变其正确性系统。 如果这个理论成立,我们刚刚将Liskov替代原则引入到代码库中,而不会吓倒任何他们不明白的高眉概念的人:)
链接地址: http://www.djcxy.com/p/82273.html上一篇: How to understand the big picture in a loose coupled application?