Loose Coupling in Object Oriented Design

I am trying to learn GRASP and I found this explained (here on page 3) about Low Coupling and I was very surprised when I found this:

Consider the method addTrack for an Album class, two possible methods are:

addTrack( Track t )

and

addTrack( int no, String title, double duration )

Which method reduces coupling?
The second one does, since the class using the Album class does not have to know a Track class.
In general, parameters to methods should use base types (int, char …) and classes from the java.* packages.

I tend to diasgree with this; I believe addTrack(Track t) is better than addTrack(int no, String title, double duration) due to various reasons:

  1. It is always better for a method to as fewer parameters as possible (according to Uncle Bob’s Clean Code none or one preferably, 2 in some cases and 3 in special cases; more than 3 needs refactoring – these are of course recommendations not holly rules).

  2. If addTrack is a method of an interface, and the requirements need that a Track should have more information (say year or genre) then the interface needs to be changed and so that the method should supports another parameter.

  3. Encapsulation is broke; if addTrack is in an interface, then it should not know the internals of the Track.

  4. It is actually more coupled in the second way, with many parameters. Suppose the no parameter needs to be changed from int to long because there are more than MAX_INT tracks (or for whatever reason); then both the Track and the method need to be changed while if the method would be addTrack(Track track) only the Track would be changed.

All the 4 arguments are actually connected with each other, and some of them are consequences from others.

Which approach is better?

8

Well, your first three points are actually about other principles than coupling. You always have to strike a balance between oft-conflicting design principles.

Your fourth point is about coupling, and I strongly agree with you. Coupling is about the flow of data between modules. The type of the container that data flows in is largely immaterial. Passing a duration as a double instead of as a field of a Track doesn’t obviate the need to pass it. The modules still need to share the same amount of data, and still have the same amount of coupling.

He is also failing to consider all the coupling in the system as an aggregate. While introducing a Track class admittedly adds another dependency between two individual modules, it can significantly reduce the coupling of the system, which is the important measure here.

For example, consider an “Add to Playlist” button and a Playlist object. Introducing a Track object could be considered to increase coupling if you only consider those two objects. You now have three interdependent classes instead of two. However, that is not the entirety of your system. You also need to import the track, play the track, display the track, etc. Adding one more class to that mix is negligible.

Now consider needing to add support for playing tracks over the network instead of just locally. You just need to create a NetworkTrack object that conforms to the same interface. Without the Track object, you would have to create functions everywhere like:

addNetworkTrack(int no, string title, double duration, URL location)

That effectively doubles your coupling, requiring even modules that don’t care about the network-specific stuff to nevertheless still keep track of it, in order to be able to pass it on.

Your ripple effect test is a good one to determine your true amount of coupling. What we are concerned with is limiting the places a change affects.

4

My recommendation is:

Use

addTrack( ITrack t )

but be sure that ITrack is an interface and not a concrete class.

Album doesn’t know the internals of ITrack implementors. It’s only coupled to the contract defined by the ITrack.

I think this is the solution that generates the least amount of coupling.

5

I would argue that the second example method most likely increases coupling, since it most likely is instantiating a Track object and storing it in the current Album object. (As suggested in my comment above, I would assume it to be inherent that an Album class would have the concept of a Track class somewhere inside it.)

The first example method assumes that a Track is getting instantiated outside the Album class, so at the very least, we can assume that the instantiation of the Track class is not coupled to the Album class.

If best practices suggested that we never have one class reference a second class, the entirety of object-oriented programming would be thrown out the window.

2

Coupling is just one of many aspects to try to obtain in your code. By reducing coupling, you’re not necessarily improving your program. In general, this is a best practice, but in this particular instance, why shouldn’t Track be known?

By using a Track class to be passed to Album, you are making your code easier to read, but more importantly, as you mentioned, you’re turning a static list of parameters into a dynamic object. That ultimately makes your interface far more dynamic.

You mention that encapsulation is broke, but it is not. Album must know the internals of Track, and if you did not use an object, Album would have to know each and every piece of information passed to it before it could make use of it all the same. The caller must know the internals of Track as well, since it must construct a Track object, but the caller must know this information all the same if it were passed directly to the method. In other words, if the advantage of encapsulation is not knowing an object’s contents, it could not possibly be used in this case since Album must make use of Track‘s information just the same.

Where you wouldn’t want to use Track is if Track contains internal logic that you wouldn’t want the caller to have access to. In other words, if Album were a class that a programmer using your library were to use, you wouldn’t want him to use Track if you use it to say, call a method to persist it on the database. The true problem with this lies in the fact that the interface is entangled with the model.

To fix the problem, you would need to separate Track into its interface components and its logic components, creating two separate classes. To the caller, Track becomes a light class which is meant to hold information and offer minor optimizations (calculated data and/or default values). Inside Album, you would use a class named TrackDAO to perform the heavy lifting associated with saving the information from Track to the database.

Of course, this is just an example. I’m sure this is not your case at all, and so feel free to use Track guilt-free. Just remember to keep your caller in mind when you’re constructing classes and to create interfaces when required.

0

Both are correct

addTrack( Track t ) 

is better (as you already argumented) while

addTrack( int no, String title, double duration ) 

is less coupled because the code that uses addTrack does not need to know that there is a Track class. Track can be renamed for example without the need to update the calling code.

While you are talking about more readable/maintainable code the article is talking about coupling.
Less coupled code is not necessarily easier to implement and to understand.

1

Low Coupling doesn’t mean No Coupling. Something, somewhere, has to know about objects elsewhere in the codebase, and the more you reduce dependence on “custom” objects, the more reasons you give for code to change. What the author you cite is promoting with the second function is less coupled, but also less object-oriented, which is contrary to the entire idea of GRASP as being an object-oriented design methodology. The whole point is how to design the system as a collection of objects and their interactions; avoiding them is like teaching you how to drive a car by saying you should ride a bike instead.

Instead, the proper avenue is to reduce dependence on concrete objects, which is the theory of “loose coupling”. The fewer definite concrete types a method has to have knowledge of, the better. Just by that statement, the first option is actually less coupled, because the second method taking the simpler types must know about all of those simpler types. Sure they’re built-in, and the code inside the method may have to care, but the signature of the method and the method’s callers most definitely do not. Changing one of these parameters relating to a conceptual audio track is going to require more changes when they’re separate versus when they’re contained in a Track object (which is the point of objects; encapsulation).

Going one step further, if Track were expected to be replaced with something that did the same job better, perhaps an interface defining the requisite functionality would be in order, an ITrack. That could allow for differing implementations such as “AnalogTrack”, “CdTrack” and “Mp3Track” that provided additional information more specific to those formats, while still providing the basic data exposure of ITrack that conceptually represents a “track”; a finite sub-piece of audio. Track could similarly be an abstract base class, but this requires you to always want to use the implementation inherent in Track; reimplement it as BetterTrack and now you have to change out the expected parameters.

Thus the golden rule; programs and their code components will always have reasons to change. You can’t write a program that will never require editing code you’ve already written in order to add something new or modify its behavior. Your goal, in any methodology (GRASP, SOLID, any other acronym or buzzword you can think of) is simply to identify the things that will have to change over time, and design the system so that those changes are as easy to make as possible (translated; touching as few lines of code and affecting as few other areas of the system beyond the scope of your intended change as possible). Case in point, what’s most likely to change is that a Track will gain more data members that addTrack() may or may not care about, not that Track will be replaced with BetterTrack.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

Loose Coupling in Object Oriented Design

I am trying to learn GRASP and I found this explained (here on page 3) about Low Coupling and I was very surprised when I found this:

Consider the method addTrack for an Album class, two possible methods are:

addTrack( Track t )

and

addTrack( int no, String title, double duration )

Which method reduces coupling?
The second one does, since the class using the Album class does not have to know a Track class.
In general, parameters to methods should use base types (int, char …) and classes from the java.* packages.

I tend to diasgree with this; I believe addTrack(Track t) is better than addTrack(int no, String title, double duration) due to various reasons:

  1. It is always better for a method to as fewer parameters as possible (according to Uncle Bob’s Clean Code none or one preferably, 2 in some cases and 3 in special cases; more than 3 needs refactoring – these are of course recommendations not holly rules).

  2. If addTrack is a method of an interface, and the requirements need that a Track should have more information (say year or genre) then the interface needs to be changed and so that the method should supports another parameter.

  3. Encapsulation is broke; if addTrack is in an interface, then it should not know the internals of the Track.

  4. It is actually more coupled in the second way, with many parameters. Suppose the no parameter needs to be changed from int to long because there are more than MAX_INT tracks (or for whatever reason); then both the Track and the method need to be changed while if the method would be addTrack(Track track) only the Track would be changed.

All the 4 arguments are actually connected with each other, and some of them are consequences from others.

Which approach is better?

8

Well, your first three points are actually about other principles than coupling. You always have to strike a balance between oft-conflicting design principles.

Your fourth point is about coupling, and I strongly agree with you. Coupling is about the flow of data between modules. The type of the container that data flows in is largely immaterial. Passing a duration as a double instead of as a field of a Track doesn’t obviate the need to pass it. The modules still need to share the same amount of data, and still have the same amount of coupling.

He is also failing to consider all the coupling in the system as an aggregate. While introducing a Track class admittedly adds another dependency between two individual modules, it can significantly reduce the coupling of the system, which is the important measure here.

For example, consider an “Add to Playlist” button and a Playlist object. Introducing a Track object could be considered to increase coupling if you only consider those two objects. You now have three interdependent classes instead of two. However, that is not the entirety of your system. You also need to import the track, play the track, display the track, etc. Adding one more class to that mix is negligible.

Now consider needing to add support for playing tracks over the network instead of just locally. You just need to create a NetworkTrack object that conforms to the same interface. Without the Track object, you would have to create functions everywhere like:

addNetworkTrack(int no, string title, double duration, URL location)

That effectively doubles your coupling, requiring even modules that don’t care about the network-specific stuff to nevertheless still keep track of it, in order to be able to pass it on.

Your ripple effect test is a good one to determine your true amount of coupling. What we are concerned with is limiting the places a change affects.

4

My recommendation is:

Use

addTrack( ITrack t )

but be sure that ITrack is an interface and not a concrete class.

Album doesn’t know the internals of ITrack implementors. It’s only coupled to the contract defined by the ITrack.

I think this is the solution that generates the least amount of coupling.

5

I would argue that the second example method most likely increases coupling, since it most likely is instantiating a Track object and storing it in the current Album object. (As suggested in my comment above, I would assume it to be inherent that an Album class would have the concept of a Track class somewhere inside it.)

The first example method assumes that a Track is getting instantiated outside the Album class, so at the very least, we can assume that the instantiation of the Track class is not coupled to the Album class.

If best practices suggested that we never have one class reference a second class, the entirety of object-oriented programming would be thrown out the window.

2

Coupling is just one of many aspects to try to obtain in your code. By reducing coupling, you’re not necessarily improving your program. In general, this is a best practice, but in this particular instance, why shouldn’t Track be known?

By using a Track class to be passed to Album, you are making your code easier to read, but more importantly, as you mentioned, you’re turning a static list of parameters into a dynamic object. That ultimately makes your interface far more dynamic.

You mention that encapsulation is broke, but it is not. Album must know the internals of Track, and if you did not use an object, Album would have to know each and every piece of information passed to it before it could make use of it all the same. The caller must know the internals of Track as well, since it must construct a Track object, but the caller must know this information all the same if it were passed directly to the method. In other words, if the advantage of encapsulation is not knowing an object’s contents, it could not possibly be used in this case since Album must make use of Track‘s information just the same.

Where you wouldn’t want to use Track is if Track contains internal logic that you wouldn’t want the caller to have access to. In other words, if Album were a class that a programmer using your library were to use, you wouldn’t want him to use Track if you use it to say, call a method to persist it on the database. The true problem with this lies in the fact that the interface is entangled with the model.

To fix the problem, you would need to separate Track into its interface components and its logic components, creating two separate classes. To the caller, Track becomes a light class which is meant to hold information and offer minor optimizations (calculated data and/or default values). Inside Album, you would use a class named TrackDAO to perform the heavy lifting associated with saving the information from Track to the database.

Of course, this is just an example. I’m sure this is not your case at all, and so feel free to use Track guilt-free. Just remember to keep your caller in mind when you’re constructing classes and to create interfaces when required.

0

Both are correct

addTrack( Track t ) 

is better (as you already argumented) while

addTrack( int no, String title, double duration ) 

is less coupled because the code that uses addTrack does not need to know that there is a Track class. Track can be renamed for example without the need to update the calling code.

While you are talking about more readable/maintainable code the article is talking about coupling.
Less coupled code is not necessarily easier to implement and to understand.

1

Low Coupling doesn’t mean No Coupling. Something, somewhere, has to know about objects elsewhere in the codebase, and the more you reduce dependence on “custom” objects, the more reasons you give for code to change. What the author you cite is promoting with the second function is less coupled, but also less object-oriented, which is contrary to the entire idea of GRASP as being an object-oriented design methodology. The whole point is how to design the system as a collection of objects and their interactions; avoiding them is like teaching you how to drive a car by saying you should ride a bike instead.

Instead, the proper avenue is to reduce dependence on concrete objects, which is the theory of “loose coupling”. The fewer definite concrete types a method has to have knowledge of, the better. Just by that statement, the first option is actually less coupled, because the second method taking the simpler types must know about all of those simpler types. Sure they’re built-in, and the code inside the method may have to care, but the signature of the method and the method’s callers most definitely do not. Changing one of these parameters relating to a conceptual audio track is going to require more changes when they’re separate versus when they’re contained in a Track object (which is the point of objects; encapsulation).

Going one step further, if Track were expected to be replaced with something that did the same job better, perhaps an interface defining the requisite functionality would be in order, an ITrack. That could allow for differing implementations such as “AnalogTrack”, “CdTrack” and “Mp3Track” that provided additional information more specific to those formats, while still providing the basic data exposure of ITrack that conceptually represents a “track”; a finite sub-piece of audio. Track could similarly be an abstract base class, but this requires you to always want to use the implementation inherent in Track; reimplement it as BetterTrack and now you have to change out the expected parameters.

Thus the golden rule; programs and their code components will always have reasons to change. You can’t write a program that will never require editing code you’ve already written in order to add something new or modify its behavior. Your goal, in any methodology (GRASP, SOLID, any other acronym or buzzword you can think of) is simply to identify the things that will have to change over time, and design the system so that those changes are as easy to make as possible (translated; touching as few lines of code and affecting as few other areas of the system beyond the scope of your intended change as possible). Case in point, what’s most likely to change is that a Track will gain more data members that addTrack() may or may not care about, not that Track will be replaced with BetterTrack.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật