我正在阅读Steve McConell的Code Complete,我正在考虑他在松散耦合的一节中给出的一个例子.它是关于计算员工假期数量的方法的界面,该方法是根据员工的入职日期及其销售额计算得出的.作者建议将输入日期和销售作为方法的参数而不是雇员的实例:
int holidays(Date entryDate, Number sales)
代替
int holidays(Employee emp)
这个论点是,这解耦了方法的客户端,因为它不需要知道关于Employee类的任何信息.
我想到了两件事:
提供计算所需的所有参数会破坏封装.它显示了该方法的内部结构如何计算结果.
更改更难,例如当有人决定员工的年龄也应该包含在计算中时.人们必须改变签名.
你怎么看?
我用你的参数2看到的问题是
您假设每个所需的值都来自Employee实例.这绝不是真的.例如,假设您必须考虑公司的财务状况来计算"奖励假期"给予任何员工多少.您是否会将财务状态信息添加到员工类以避免更改签名?
更改签名不一定"更难",特别是在这些日子里,只需点击一下按钮就会突出显示每个调用位置.
你的第一个参数的主要问题是,它并没有像其他人所说的那样打破封装.您正在展示封装的内容,而不是封装的内容.
最终松散的耦合赢了.从高耦合到低耦合,有各种类型的耦合:
内容耦合(高):一个模块修改或依赖于另一个模块的内部工作
公共耦合:两个模块共享相同的全局数据(例如全局变量).更改共享资源意味着更改使用它的所有模块.
外部耦合:两个模块共享外部施加的数据格式,通信协议或设备接口.
控制耦合:一个模块控制另一个模块的逻辑,通过传递信息来做什么(例如传递一个什么做标志).
邮票耦合(数据结构耦合):当模块共享复合数据结构并仅使用其中的一部分时,可能是不同的部分(例如,将整个记录传递给只需要一个字段的函数).
数据耦合:当模块通过例如参数共享数据时.每个数据都是一个基本部分,这些是唯一共享的数据(例如,将整数传递给计算平方根的函数).
消息耦合(低):模块不依赖于彼此,而是使用公共接口来交换无参数消息(或事件,请参阅消息传递).
无耦合:模块根本不相互通信.
传入Employee
是印记耦合,它比数据耦合更加耦合.如果你真的考虑到易于修改,低耦合效果更好,因为你不必担心不必要的副作用.假设您要更改Employee
类的结构.您现在必须检查假期函数的实际实现,以确保它不会破坏数学.
最好的解耦方式是定义一个接口IHolidayable
,但这对于这种情况来说太过分了.