The problems I see with your argument number 2 are
you are assuming every needed value comes from an Employee instance. This is by no means always true. For example, say you have to consider the financial state of the company to calculate how much 'bonus holiday' give to any employee. Would you add financial state information to the employee class to avoid changing the signature?
changing a signature is not necessarily "harder", especially so in these days of tools that will highlight every calling place at the click of a button.
And the main problem with your argument number 1 is that it just doesn't break encapsulation as everyone else has said. You are showing the what, not the how, which is what encapsulation is about.
Ultimately loose coupling wins. From high coupling to low, there are various classes of coupling:
Content coupling (high): One module modifies or relies on the internal workings of another module
Common coupling: two modules share the same global data (e.g. a global variable). Changing the shared resource implies changing all the modules using it.
External coupling: two modules share an externally imposed data format, communication protocol, or device interface.
Control coupling: one module controlling the logic of another, by passing it information on what to do (e.g. passing a what-to-do flag).
Stamp coupling (Data-structured coupling): when modules share a composite data structure and use only a part of it, possibly a different part (e.g. passing a whole record to a function which only needs one field of it).
Data coupling: when modules share data through, for example, parameters. Each datum is an elementary piece, and these are the only data which are shared (e.g. passing an integer to a function which computes a square root).
Message coupling (low): Modules are not dependent on each other, instead they use a public interface to exchange parameter-less messages (or events, see Message passing).
No coupling: Modules do not communicate at all with one another.
Passing in Employee is Stamp coupling, which is more coupled than Data coupling. If you really think about the ease of modification, low coupling is better because you have less to worry about the unwanted side effects. Suppose you want to change the structure of the Employee class. You now have to check the actual implementation of the holidays function to make sure that it doesn't break the math.
The best most decoupled way is to define an interface IHolidayable, but that's an overkill for this situation.
对我来说,“正确”的答案归结为您在创建此函数时是定义高级 API 还是低级 API。 对于任何特定情况,低级 API 将灵活性置于便利性之上,并支持 intholidays(Date entryDate, Number sales) 。 高级 API 旨在为客户提供尽可能多的便利,做好一件事。 这支持 intholidays(Employee emp),因为它在调用者方面需要较少的样板文件(从 Employee 类中提取日期和销售额)并且不那么冗长。
To me the "right" answer boils down to whether you're defining a high-level or low-level API when creating this function. A low-level API puts flexibility above convenience for any particular case and argues for int holidays(Date entryDate, Number sales) . A high-level API is designed to do one thing well with as much convenience as possible for the client. This argues for int holidays(Employee emp) because it requires less boilerplate on the caller's part (extracting the date and sales from the Employee class) and is less verbose.
1) Providing parameters doesn't break encapsulation. It just shows that these parameters are used to calculate holidays. The "HOW" is still hidden inside the method.
2) Holiday method should not be a part of Employee class.
This is not breaking encapsulation. Breaking encapsulation would be revealing the internal methods it uses to calculate the holidays. Providing the starting parameters is what defines the API.
The API could be improved to allow such changes - however, most approaches suggest that you should design to meet the requirements have currently and not to over design for unforeseen changes (design for change, but do not try to predict the change). It's better to implement what you need now and refactor later if necessary.
In my opinion it's best to plan for change by decoupling and encapsulating as much as possible so that refactoring could be done as easily as possible. Attempting to predict ahead of time every possible scenario ends up with a bloated over-designed system.
此外,我不会说您通过为方法提供参数来破坏封装。 您可以随意实现 Sum(int a, int b) - 但您必须告诉我(作为用户)您期望两个数字。
I would say that one of the major benefits of loose coupling is the ease of change. Loosely coupled types can change independently of each other so I don't understand your "vs" in the question.
Additionally, I would not say that you break encapsulation by providing parameters for the method. You can implement a Sum(int a, int b) anyway you want - but you have to tell me (as the user) that you expect two numbers.
Unlike some other posts i agree with you that this breaks encapsulation. Not the encapsulation of a class, but of the concept of calculating holidays. If you want to change how this calculation works in the future, and still avoid tight coupling, i would suggest making Employee an interface. If this is still too tightly coupled to Employee because you think holidays might need to be calculated for other things, then you could have a GetsHolidays interface from which Employee inherits.
Of course, how involved the solution you choose is should depend on how serious you consider the coupling and encapsulation problems to be. I would consider both the original solutions to be acceptable in many situations, keep it simple if possible.
The best most decoupled way is to define an interface IHolidayable
This sort of blanket statement really annoys me. Just because you use an interface does NOT mean you automatically decouple anything. If your employee class implements an interface to calculate holidays, any code that calls the method, still calls the same method. At worst, the calling code will do that by direct access to an employee object, not an IHolidayable interface reference, in which case you have only made the situation worse (because there is now also a more subtle coupling between the interface and any classes which implement it).
Interfaces can indeed help with decoupling, but they do not automatically do so, and even when they do, they are not necessarily a better solution than an abstract (or some other ancestor) class.
发布评论
评论(10)
我在你的参数 2 中看到的问题是
更改签名不一定“更难”,尤其是在当今的工具中,单击按钮即可突出显示每个调用位置。
你的第一个论点的主要问题是它并没有像其他人所说的那样破坏封装。 您正在展示什么,而不是如何,这就是封装的意义所在。
The problems I see with your argument number 2 are
you are assuming every needed value comes from an Employee instance. This is by no means always true. For example, say you have to consider the financial state of the company to calculate how much 'bonus holiday' give to any employee. Would you add financial state information to the employee class to avoid changing the signature?
changing a signature is not necessarily "harder", especially so in these days of tools that will highlight every calling place at the click of a button.
And the main problem with your argument number 1 is that it just doesn't break encapsulation as everyone else has said. You are showing the what, not the how, which is what encapsulation is about.
最终松散的耦合获胜。 从高耦合到低耦合,有各种不同的耦合类别:
传入
Employee
是Stamp耦合,比Data耦合耦合性更强。 如果您真正考虑修改的方便性,那么低耦合会更好,因为您不必担心不需要的副作用。 假设您要更改Employee
类的结构。 您现在必须检查假期函数的实际实现,以确保它不会破坏数学。最好的解耦方法是定义一个接口
IHolidayable
,但这对于这种情况来说有点过分了。Ultimately loose coupling wins. From high coupling to low, there are various classes of coupling:
Passing in
Employee
is Stamp coupling, which is more coupled than Data coupling. If you really think about the ease of modification, low coupling is better because you have less to worry about the unwanted side effects. Suppose you want to change the structure of theEmployee
class. You now have to check the actual implementation of the holidays function to make sure that it doesn't break the math.The best most decoupled way is to define an interface
IHolidayable
, but that's an overkill for this situation.对我来说,“正确”的答案归结为您在创建此函数时是定义高级 API 还是低级 API。 对于任何特定情况,低级 API 将灵活性置于便利性之上,并支持
intholidays(Date entryDate, Number sales)
。 高级 API 旨在为客户提供尽可能多的便利,做好一件事。 这支持intholidays(Employee emp)
,因为它在调用者方面需要较少的样板文件(从 Employee 类中提取日期和销售额)并且不那么冗长。To me the "right" answer boils down to whether you're defining a high-level or low-level API when creating this function. A low-level API puts flexibility above convenience for any particular case and argues for
int holidays(Date entryDate, Number sales)
. A high-level API is designed to do one thing well with as much convenience as possible for the client. This argues forint holidays(Employee emp)
because it requires less boilerplate on the caller's part (extracting the date and sales from the Employee class) and is less verbose.1)提供参数不会破坏封装。 它只是说明这些参数是用来计算假期的。 “如何”仍然隐藏在方法内部。
2) Holiday 方法不应该是 Employee 类的一部分。
1) Providing parameters doesn't break encapsulation. It just shows that these parameters are used to calculate holidays. The "HOW" is still hidden inside the method.
2) Holiday method should not be a part of Employee class.
在这种情况下,只有员工可以使用相关功能......
In this case only an employee can use the function in question...
这并没有破坏封装。 打破封装将揭示它用来计算假期的内部方法。 提供启动参数就是定义 API 的内容。
可以改进 API 以允许此类更改 - 但是,大多数方法建议您应该进行设计以满足当前的要求,而不是针对不可预见的更改进行过度设计(为更改而设计,但不要尝试预测更改) 。 最好现在实现您需要的内容,并在必要时进行重构。
可以
在我看来,最好通过尽可能多的解耦和封装来规划变更,以便尽可能轻松地进行重构。 试图提前预测每种可能的情况最终会导致系统设计过度臃肿。
This is not breaking encapsulation. Breaking encapsulation would be revealing the internal methods it uses to calculate the holidays. Providing the starting parameters is what defines the API.
The API could be improved to allow such changes - however, most approaches suggest that you should design to meet the requirements have currently and not to over design for unforeseen changes (design for change, but do not try to predict the change). It's better to implement what you need now and refactor later if necessary.
In my opinion it's best to plan for change by decoupling and encapsulating as much as possible so that refactoring could be done as easily as possible. Attempting to predict ahead of time every possible scenario ends up with a bloated over-designed system.
我想说松耦合的主要好处之一是易于更改。 松散耦合的类型可以彼此独立地改变,所以我不明白你在问题中的“vs”。
此外,我不会说您通过为方法提供参数来破坏封装。 您可以随意实现
Sum(int a, int b)
- 但您必须告诉我(作为用户)您期望两个数字。I would say that one of the major benefits of loose coupling is the ease of change. Loosely coupled types can change independently of each other so I don't understand your "vs" in the question.
Additionally, I would not say that you break encapsulation by providing parameters for the method. You can implement a
Sum(int a, int b)
anyway you want - but you have to tell me (as the user) that you expect two numbers.与其他一些帖子不同,我同意你的观点,这打破了封装。 不是类的封装,而是计算假期概念的封装。 如果您想在将来更改此计算的工作方式,并且仍然避免紧密耦合,我建议将 Employee 设为一个接口。 如果这仍然与 Employee 耦合太紧密,因为您认为可能需要为其他事情计算假期,那么您可以拥有一个 Employee 继承的 GetsHolidays 接口。
当然,您选择的解决方案的复杂程度应该取决于您认为耦合和封装问题的严重程度。 我认为这两种原始解决方案在许多情况下都是可以接受的,如果可能的话保持简单。
Unlike some other posts i agree with you that this breaks encapsulation. Not the encapsulation of a class, but of the concept of calculating holidays. If you want to change how this calculation works in the future, and still avoid tight coupling, i would suggest making Employee an interface. If this is still too tightly coupled to Employee because you think holidays might need to be calculated for other things, then you could have a GetsHolidays interface from which Employee inherits.
Of course, how involved the solution you choose is should depend on how serious you consider the coupling and encapsulation problems to be. I would consider both the original solutions to be acceptable in many situations, keep it simple if possible.
这种笼统的声明真的让我很恼火。 仅仅因为您使用接口并不意味着您会自动解耦任何东西。 如果您的员工类实现了一个计算假期的接口,则任何调用该方法的代码仍然会调用相同的方法。 在最坏的情况下,调用代码将通过直接访问雇员对象而不是 IHolidayable 接口引用来实现这一点,在这种情况下,您只会使情况变得更糟(因为现在接口和任何类之间存在更微妙的耦合)实施它)。
接口确实可以帮助解耦,但它们不会自动这样做,即使它们这样做,它们也不一定是比抽象(或其他祖先)类更好的解决方案。
This sort of blanket statement really annoys me. Just because you use an interface does NOT mean you automatically decouple anything. If your employee class implements an interface to calculate holidays, any code that calls the method, still calls the same method. At worst, the calling code will do that by direct access to an employee object, not an IHolidayable interface reference, in which case you have only made the situation worse (because there is now also a more subtle coupling between the interface and any classes which implement it).
Interfaces can indeed help with decoupling, but they do not automatically do so, and even when they do, they are not necessarily a better solution than an abstract (or some other ancestor) class.
可能是一种方法。 在这种情况下,任何实现 IHolidayInfo 的对象都可以使用“holidays”函数。 只是一个替代方案。
Is might be a way. In this case, any object that implements
IHolidayInfo
would able to use "holidays" function. Just an alternative.