CSC/ECE 517 Fall 2007/wiki3 3 aa: Difference between revisions
No edit summary |
No edit summary |
||
(22 intermediate revisions by the same user not shown) | |||
Line 9: | Line 9: | ||
==ISP in OO Design== | ==ISP in OO Design== | ||
When clients are forced to depend upon interfaces that they don’t use, then those clients are subject to changes to those interfaces. This results in an inadvertent coupling between all the clients. Said another way, when a client depends upon a class that contains interfaces that the client does not use, but that other clients do use, then that client will be affected by the changes that those other clients force upon the class. This relationship is illustrated below, where Fig.1 indicates OO Design without ISP and Fig.2 indicates OO Design with ISP. We would like to avoid such couplings where possible, and so we want to separate the interfaces where possible. | When clients are forced to depend upon interfaces that they don’t use, then those clients are subject to changes to those interfaces. This results in an inadvertent coupling between all the clients. Said another way, when a client depends upon a class that contains interfaces that the client does not use, but that other clients do use, then that client will be affected by the changes that those other clients force upon the class. This relationship is illustrated below, where Fig.1 indicates OO Design without ISP and Fig.2 indicates OO Design with ISP. We would like to avoid such couplings where possible, and so we want to separate the interfaces where possible. ISP is about high cohesion in the interface level. It is often referred to as poor man's Single Responsibility Principle (SRP) because SRP deals with cohesion at the class level. | ||
Line 25: | Line 25: | ||
===Example 1=== | ===Example 1=== | ||
The following example is a very easy to understand example of how ISP can be employed in a real world system design | The following example is a very easy to understand example of how ISP can be employed in a real world system design. | ||
Consider a cell phone had interfaces of a phone and a MP3 player. ISP advises to keep these two interfaces completely independent of each other. This way the phone can be treated purely as a phone or as a MP3 player. Programmatically,use only the interface of a MP3 player in an implemented method called playSong. In future even if the interface for the phone is modified, the method playSong would remain the same[3]. | |||
This example can be used to give a general overview of ISP, without going into much detail of how ISP is used in making complex OO design decision. | |||
===Example 2=== | ===Example 2=== | ||
The following is an example | The following example is best example that shows how ISP is used to deal with fat interfaces. In the illustrations below, UML (Unified Modeling Language) has been used to bring out the design decisions that have been made. | ||
Consider a security system. In this system there are Door objects that can be locked and unlocked, and which know whether they are open or closed. The Door class is abstract so that clients can use objects that conform to the Door interface, without having to depend upon particular implementations of Door. Now consider that one such implementation. TimedDoor needs to sound an alarm when the door has been left open for too long. In order to do this the TimedDoor object communicates with another object called a Timer. | |||
How can we get the TimerClient class to communicate with the TimedDoor class so that the code in the TimedDoor can be notified of the timeout? We force Door, and therefore TimedDoor, to inherit from TimerClient. This ensures that TimerClient can register itself with the Timer and receive the TimeOut message. | |||
Although this solution is common, it is not without problems. Chief among these is that the Door class now depends upon TimerClient. Not all varieties of Door need timing. Indeed, the original Door abstraction had nothing whatever to do with timing. If timingfree derivatives of Door are created, those derivatives will have to provide nil implementations for the TimeOut method. Moreover, the applications that use those derivatives will have to include the definition of the TimerClient class, even though it is not used. | |||
Figure 3 shows a common syndrome of object oriented design in statically typed languages like C++. This is the syndrome of interface pollution. The interface of Door has been polluted with an interface that it does not require. It has been forced to incorporate this interface solely for the benefit of one of its subclasses. If this practice is pursued, then every time a derivative needs a new interface, that interface will be added to the base class. This will further pollute the interface of the base class, making it “fat” | |||
Moreover, each time a new interface is added to the base class, that interface must be implemented (or allowed to default) in derived classes. Indeed, an associated practice is to add these interfaces to the base class as | |||
nil virtual functions rather than pure virtual functions; specifically so that derived classes are not burdened with the need to implement them. As we learned in class, such a practice violates the Liskov Substitution principle (LSP), leading to maintenance and reusability problems. | |||
The solution to these problems are intriguing. The answer to this lies in the fact that clients of an object do not need to access it through the interface of the object. Rather, they can access it through delegation, or through a base class of the object. | |||
Figure 4 show how Multiple Inheritance can be used, in the class form of the ADAPTER pattern, to achieve the ISP. In this model, TimedDoor inherits from both Door and TimerClient. Although clients of both base classes can make use of TimedDoor, neither actually depend upon the TimedDoor class. Thus, they use the same object through separate interfaces [2]. | |||
[[Image:isp3.jpg|thumb|left|300x350px|Fig.3) Timed Door Design without ISP]] | |||
[[Image:isp4.jpg|thumb|none|460x420px|Fig.4) Timed Door Design with ISP]] | |||
'''Out of all the four examples that are presented in this article we consider this the most suitable to be taught in class. | |||
''' | |||
===Example 3=== | |||
The following example deals with the design of UI for a client-sever architecture. Consider a system in which the user has a choice of three types of UIs, namely GUI (Graphical User Interface), Touchpad and a Console. There is a central server that has to satisfy the request from clients, collects the display interfaces and displays customized result back to the user (Server class). In a system without ISP, addition of a new type of UI, will require a changes in the server interface. Furthermore, it would also require all the other UIs to be recompiled. If proper ISP is applied in the OO Design, new UIs can be added without requiring changes to the server's interfaces. Also the other UIs are not affected. The Fig.5 illustrates this example. | |||
The ISP are implemented by using an intermediary interfaces that interact with the server. These intermediary interfaces implement common functionality of each of the UIs, thus abstracting the actual implementation of the UIs from the server class. Hence new UIs can be added without requiring change to the server and other UIs[4]. | |||
[[Image:isp5.jpg|thumb|center|425x420px|Fig.5) UI Design ]] | |||
===Example 4=== | |||
Consider a slightly more significant example. The traditional Automated Teller Machine (ATM) problem. The user interface of an ATM machine needs to be very flexible. The output may need to be translated into many different language. It may need to be presented on a screen, or on a braille tablet, or spoken out a speech synthesizer. Clearly this can be achieved by creating an abstract base class that has pure virtual functions for all the different messages that need to be presented by the interface. Fig.6 Represents a general UI design for the ATM. | |||
[[Image:ATM_UI.jpg|thumb|center|400x400px|Fig.6) ATM UI Design ]] | |||
Also consider that different transactions that the ATM can perform is encapsulated as a derivative of the class Transaction. Thus we might have classes such as DepositTransaction, WithdrawlTransaction, TransferTransaction, etc. Each of these objects issues message | |||
to the UI. For example, the DepositTransaction object calls the RequestDepositAmount member function of the UI class. Whereas the transferTransaction object calls the RequestTransferAmount member function of UI. This corresponds to the diagram in Figure 7. | |||
[[Image: | [[Image:ATM_TRN.jpg|thumb|center|400x400px|Fig.7) ATM TRANSACTION Design ]] | ||
Notice that this is precisely the situation that the ISP tells us to avoid. Each of the transactions is using a portion of the UI that no other object uses. This creates the possibility that changes to one of the derivatives of Transaction will force corresponding change to the UI, thereby affecting all the other derivatives of Transaction, and every other class that depends upon the UI interface. | |||
This unfortunate coupling can be avoided by segregating the UI interface into individual abstract base classes such as DepositUI, withdrawUI and TransferUI. These abstract base classes can then be multiply inherited into the final UI abstract class. Fig.8 show this model[5]. | |||
[[Image:segregation.jpg|thumb|center|400x400px|Fig.8) ATM SEGREGATION Design ]] | |||
==Catalog== | ==Catalog / Reference== | ||
http://www.objectmentor.com/resources/articles/isp.pdf | 1. [http://www.objectmentor.com/resources/articles/isp.pdf objectMentor]<br> | ||
http://doodleproject.sourceforge.net/articles/2001/interfaceSegregationPrinciple.html | 2. [http://doodleproject.sourceforge.net/articles/2001/interfaceSegregationPrinciple.html doodleproject]<br> | ||
http://ifacethoughts.net/2006/03/28/interface-segregation-principle/ | 3. [http://ifacethoughts.net/2006/03/28/interface-segregation-principle/ ifacethoughts] <br> | ||
http://www.everything2.com/index.pl?node_id=1259576 | 4. [http://www.everything2.com/index.pl?node_id=1259576 everything_oo]<br> | ||
http://www.cmcrossroads.com/articles/agile-cm-environments/principles-of-agile-version-control:-from-ood-to-tbd.html | 5. [http://www.cmcrossroads.com/articles/agile-cm-environments/principles-of-agile-version-control:-from-ood-to-tbd.html cmc_oodesign]<br> | ||
http://jayflowers.com/WordPress/?p=91 | 6. [http://jayflowers.com/WordPress/?p=91 jayflowers]<br> | ||
http://www.cet.sunderland.ac.uk/~cs0her/COM379%20Lectures/Lecture3.ppt | 7. [http://www.cet.sunderland.ac.uk/~cs0her/COM379%20Lectures/Lecture3.ppt sunderland_technologies]<br> | ||
http://www.parlezuml.com/metrics/OO%20Design%20Principles%20&%20Metrics.pdf | 8. [http://www.parlezuml.com/metrics/OO%20Design%20Principles%20&%20Metrics.pdf uml]<br> | ||
9. [http://javaboutique.internet.com/tutorials/JavaOO/interface_segregation.html javaboutique]<br> | |||
10.[http://www.ddj.com/blog/architectblog/archives/2006/06/interface_segre.html arch_of_oo]<br> | |||
11.[http://hocit.com/forum/showthread.php?p=13932 OOforum]<br> |
Latest revision as of 17:41, 19 November 2007
Topic
Take the Interface Segregation principle and catalog the information on it available on the Web. We didn't cover it in class, but you can look it up on the Web or in the ACM DL. Find good descriptions and good, concise, understandable examples. Tell which you consider the best to present to a class.
Interface Segregation Principle (ISP)
The Interface Segregation Principle states that "Clients should not be forced to depend upon interfaces that they do not use".
ISP in OO Design
When clients are forced to depend upon interfaces that they don’t use, then those clients are subject to changes to those interfaces. This results in an inadvertent coupling between all the clients. Said another way, when a client depends upon a class that contains interfaces that the client does not use, but that other clients do use, then that client will be affected by the changes that those other clients force upon the class. This relationship is illustrated below, where Fig.1 indicates OO Design without ISP and Fig.2 indicates OO Design with ISP. We would like to avoid such couplings where possible, and so we want to separate the interfaces where possible. ISP is about high cohesion in the interface level. It is often referred to as poor man's Single Responsibility Principle (SRP) because SRP deals with cohesion at the class level.
Without ISP, the OO Design may contain fat interfaces. "Fat" interfaces arise from classes whose member methods can be broken into two or more groups. Each group of methods in turn serves a different set of clients. The Interface Segregation Principle suggests that client should not know about the method groups as a single class. Instead, clients should know about abstract base classes, one for each method group, which have cohesive interfaces. Fat interfaces lead to inadvertent couplings between clients that ought otherwise to be isolated. By making use of the ADAPTER pattern, either through delegation (object form) or multiple inheritance (class form), fat interfaces can be segregated into abstract base classes that break the unwanted coupling between clients.
The ISP acknowledges that there are objects that require non-cohesive interfaces; however it suggests that clients should not know about them as a single class. Instead, clients should know about abstract base classes that have cohesive interfaces. Some languages refer to these abstract base classes as “interfaces”, “protocols” or “signatures”.
Examples of ISP
Example 1
The following example is a very easy to understand example of how ISP can be employed in a real world system design.
Consider a cell phone had interfaces of a phone and a MP3 player. ISP advises to keep these two interfaces completely independent of each other. This way the phone can be treated purely as a phone or as a MP3 player. Programmatically,use only the interface of a MP3 player in an implemented method called playSong. In future even if the interface for the phone is modified, the method playSong would remain the same[3].
This example can be used to give a general overview of ISP, without going into much detail of how ISP is used in making complex OO design decision.
Example 2
The following example is best example that shows how ISP is used to deal with fat interfaces. In the illustrations below, UML (Unified Modeling Language) has been used to bring out the design decisions that have been made.
Consider a security system. In this system there are Door objects that can be locked and unlocked, and which know whether they are open or closed. The Door class is abstract so that clients can use objects that conform to the Door interface, without having to depend upon particular implementations of Door. Now consider that one such implementation. TimedDoor needs to sound an alarm when the door has been left open for too long. In order to do this the TimedDoor object communicates with another object called a Timer.
How can we get the TimerClient class to communicate with the TimedDoor class so that the code in the TimedDoor can be notified of the timeout? We force Door, and therefore TimedDoor, to inherit from TimerClient. This ensures that TimerClient can register itself with the Timer and receive the TimeOut message.
Although this solution is common, it is not without problems. Chief among these is that the Door class now depends upon TimerClient. Not all varieties of Door need timing. Indeed, the original Door abstraction had nothing whatever to do with timing. If timingfree derivatives of Door are created, those derivatives will have to provide nil implementations for the TimeOut method. Moreover, the applications that use those derivatives will have to include the definition of the TimerClient class, even though it is not used.
Figure 3 shows a common syndrome of object oriented design in statically typed languages like C++. This is the syndrome of interface pollution. The interface of Door has been polluted with an interface that it does not require. It has been forced to incorporate this interface solely for the benefit of one of its subclasses. If this practice is pursued, then every time a derivative needs a new interface, that interface will be added to the base class. This will further pollute the interface of the base class, making it “fat”
Moreover, each time a new interface is added to the base class, that interface must be implemented (or allowed to default) in derived classes. Indeed, an associated practice is to add these interfaces to the base class as nil virtual functions rather than pure virtual functions; specifically so that derived classes are not burdened with the need to implement them. As we learned in class, such a practice violates the Liskov Substitution principle (LSP), leading to maintenance and reusability problems.
The solution to these problems are intriguing. The answer to this lies in the fact that clients of an object do not need to access it through the interface of the object. Rather, they can access it through delegation, or through a base class of the object.
Figure 4 show how Multiple Inheritance can be used, in the class form of the ADAPTER pattern, to achieve the ISP. In this model, TimedDoor inherits from both Door and TimerClient. Although clients of both base classes can make use of TimedDoor, neither actually depend upon the TimedDoor class. Thus, they use the same object through separate interfaces [2].
Out of all the four examples that are presented in this article we consider this the most suitable to be taught in class.
Example 3
The following example deals with the design of UI for a client-sever architecture. Consider a system in which the user has a choice of three types of UIs, namely GUI (Graphical User Interface), Touchpad and a Console. There is a central server that has to satisfy the request from clients, collects the display interfaces and displays customized result back to the user (Server class). In a system without ISP, addition of a new type of UI, will require a changes in the server interface. Furthermore, it would also require all the other UIs to be recompiled. If proper ISP is applied in the OO Design, new UIs can be added without requiring changes to the server's interfaces. Also the other UIs are not affected. The Fig.5 illustrates this example.
The ISP are implemented by using an intermediary interfaces that interact with the server. These intermediary interfaces implement common functionality of each of the UIs, thus abstracting the actual implementation of the UIs from the server class. Hence new UIs can be added without requiring change to the server and other UIs[4].
Example 4
Consider a slightly more significant example. The traditional Automated Teller Machine (ATM) problem. The user interface of an ATM machine needs to be very flexible. The output may need to be translated into many different language. It may need to be presented on a screen, or on a braille tablet, or spoken out a speech synthesizer. Clearly this can be achieved by creating an abstract base class that has pure virtual functions for all the different messages that need to be presented by the interface. Fig.6 Represents a general UI design for the ATM.
Also consider that different transactions that the ATM can perform is encapsulated as a derivative of the class Transaction. Thus we might have classes such as DepositTransaction, WithdrawlTransaction, TransferTransaction, etc. Each of these objects issues message
to the UI. For example, the DepositTransaction object calls the RequestDepositAmount member function of the UI class. Whereas the transferTransaction object calls the RequestTransferAmount member function of UI. This corresponds to the diagram in Figure 7.
Notice that this is precisely the situation that the ISP tells us to avoid. Each of the transactions is using a portion of the UI that no other object uses. This creates the possibility that changes to one of the derivatives of Transaction will force corresponding change to the UI, thereby affecting all the other derivatives of Transaction, and every other class that depends upon the UI interface.
This unfortunate coupling can be avoided by segregating the UI interface into individual abstract base classes such as DepositUI, withdrawUI and TransferUI. These abstract base classes can then be multiply inherited into the final UI abstract class. Fig.8 show this model[5].
Catalog / Reference
1. objectMentor
2. doodleproject
3. ifacethoughts
4. everything_oo
5. cmc_oodesign
6. jayflowers
7. sunderland_technologies
8. uml
9. javaboutique
10.arch_of_oo
11.OOforum