CSC/ECE 517 Fall 2010/chd 6d isb: Difference between revisions
No edit summary |
No edit summary |
||
(40 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
= Introduction = | = Introduction = | ||
The Interface Segregation Principle (ISP) focuses on the cohesiveness of interfaces with respect to the clients that use them. ISP is very similar to high cohesion principle of [http://en.wikipedia.org/wiki/GRASP_(object-oriented_design) GRASP]. ISP helps developers to change, refactor and redeploy their code easily. This principle alleviates the disadvantages of "fat" or "polluted" interfaces. [1] ISP is considered as the eye of the [http://en.wikipedia.org/wiki/Solid_(object-oriented_design) SOLID] design principle. Two main ISP guidelines are: Classes should not be forced to depend on methods that they do not use, and the dependency of one class to another one should depend on the smallest possible interface. [3] | The Interface Segregation Principle (ISP) focuses on the [http://en.wikipedia.org/wiki/Cohesion_(computer_science) cohesiveness] of interfaces with respect to the clients that use them. ISP is very similar to [http://en.wikipedia.org/wiki/Cohesion_(computer_science) high cohesion] principle of [http://en.wikipedia.org/wiki/GRASP_(object-oriented_design) GRASP]. ISP helps developers to change, refactor and redeploy their code easily. This principle alleviates the disadvantages of "fat" or "polluted" interfaces. [1] ISP is considered as the eye of the [http://en.wikipedia.org/wiki/Solid_(object-oriented_design) SOLID] design principle. Two main ISP guidelines are: Classes should not be forced to depend on methods that they do not use, and the dependency of one class to another one should depend on the smallest possible interface. [3][5] | ||
= Brief Introduction to Interfaces in OOP = | = Brief Introduction to Interfaces in OOP = | ||
In Object Oriented languages, an interface separates the implementation and defines the structure. Apart from that, an interface is very useful when the implementation changes frequently. Interface can be used to define a generic template and then one or more abstract classes to define partial implementations of the interface. Generally, interfaces are used as a group of related methods with empty bodies. Interfaces form a "contract" between the class and the outside world, and this contract is enforced at build time by the compiler. Interfaces are widely used in Object Oriented Languages such as [http://en.wikipedia.org/wiki/Java_(programming_language) Java],[http://en.wikipedia.org/wiki/C_Sharp_(programming_language) C#] and [http://en.wikipedia.org/wiki/C%2B%2B C++]. [4][7] | |||
= Fat Interfaces= | = Fat Interfaces= | ||
As stated above, ISP is used to overcome the problems introduced by "fat interfaces". In order to clarify this term, consider the example given below. | As stated above, ISP is used to overcome the problems introduced by "fat interfaces". In order to clarify this term, consider the example given below. [6] | ||
[[Image:fatinterface.jpg |center| Fat Interface Example]] | [[Image:fatinterface.jpg |center| Fat Interface Example]] | ||
Car, Motorcycle and/or Aircraft classes implement the Abstract Vehicle interface that defines methods : TurnLeft, TurnRight, DriveForwards and DriveBackwards. All these methods are going to be used by the classes which implements this interface. There will not be any problems if Car class implements this interface, since every car turns left, turns right, drives forwards and drive backwards. Assume that Aircraft class also implements Vehicle Interface. Any aircraft can turn left, turn right and drive forwards. On the other hand, no aircraft can drive backwards by itself (without and help of a special helper). Another example: if a Motorcycle class implements the Vehicle abstract interface, it has to use DriveBackwards method, although it cannot drive backwards by itself. | |||
Here, The Abstract Vehicle Interface is an example of a "fat interface". One of the side-effects of fat interfaces is that any class that implements the interface ends up doing too many things and this can clearly violate the [http://en.wikipedia.org/wiki/Single_responsibility_principle Single Responsibility Principle]. | Here, The Abstract Vehicle Interface is an example of a "fat interface". One of the side-effects of fat interfaces is that any class that implements the interface ends up doing too many things and this can clearly violate the [http://en.wikipedia.org/wiki/Single_responsibility_principle Single Responsibility Principle]. | ||
=ISP for " Fat Interfaces"= | ==ISP for " Fat Interfaces "== | ||
By breaking interfaces down into smaller chunks, we potentially reduce the responsibilities of a class and thus provide higher cohesion between the methods of a particular interface. This also provides the benefit of making a clear statement to consumers of the interface of what minimum functionality is required to be implemented: everything. There uncertainty of whether a particular method or property needs to be implemented vanishes, reducing the factor of surprise. The Vehicle interface could be decomposed into ForwardMovingVehicle and BackwardMovingVehicle. If there are classes that require both functionalities, they would implement both interfaces. Alternatively, if only one interface were required, for example for Aircraft, then only the ForwardMovingVehicle interface would be implemented, avoiding giving way to empty declarations with NotImplementedException exceptions as their implementation. | By breaking interfaces down into smaller chunks, we potentially reduce the responsibilities of a class and thus provide higher cohesion between the methods of a particular interface. This also provides the benefit of making a clear statement to consumers of the interface of what minimum functionality is required to be implemented: everything. There uncertainty of whether a particular method or property needs to be implemented vanishes, reducing the factor of surprise. The Vehicle interface could be decomposed into ForwardMovingVehicle and BackwardMovingVehicle. If there are classes that require both functionalities, they would implement both interfaces. Alternatively, if only one interface were required, for example for Aircraft, then only the ForwardMovingVehicle interface would be implemented, avoiding giving way to empty declarations with NotImplementedException exceptions as their implementation. | ||
Line 23: | Line 27: | ||
[[Image:thininterface.jpg |center| Thin Interface Example]] | [[Image:thininterface.jpg |center| Thin Interface Example]] | ||
==Interface Pollution== | |||
Interface Pollution term is used interchangeable with Fat Interfaces. Whenever an interface is added to base class, that base class does not need, base class is polluted with that interface. In other words, base class' interface has been polluted. [1] | |||
=ISP in Action= | |||
Consider the following example in order to better understand The Interface Segregation Principle. A Security system includes Door objects which has the methods given below. Now, consider a Timer class which is used to sound an alarm when the door has been left open for too long. TimedDoor object communicates Timer class to do so. | |||
[[Image:Interface1.jpg |left| Door Class]] | |||
[[Image:Interface2.png |center| Timer Class]] | |||
Whenever an object wants to be informed about an timeout, it calls Register function of the Timer class. The problem is how can the TimerClient class communicate with the TimedDoor class? Common solution is inheriting from TimerClient class. | |||
[[Image:Interface3.jpg |center| Inheritance]] | |||
The Door class depends upon TimerClient, but not all types of Door need timing. Moreover, all the applications that use those derivatives will include TimerClass methods, even though they are not using them (Interface Pollution). | |||
SInce Door and TimerClient represent interfaces for different clients. They should be separated. | |||
==Separation Through Delegation== | |||
Adapter pattern can be used to solve the problem above. The solution can be implemented by creating an adapter object that derives from TimerClient and delegates to TimedDoor. When the TimedDoor wants to register a timeout request with Timer, it creates a DoorTimerAdapter and registers with Timer class. If Timer sends the Timeout to DoorTimerAdapter, it delegates that message back to the TimedDoor. | |||
[[Image:Interface5.jpg |center| Inheritance]] | |||
The Interface Segregation Principle has been applied above. By doing so, the coupling of Door clients to Timer has been prevented. Even if Timer is changed, Door objects will not be affected. | |||
==Separation Through Multiple Inheritance== | |||
If the language developer uses supports [http://en.wikipedia.org/wiki/Multiple_inheritance Multiple Inheritance], the Interface Segregation Principle can be applied through multiple inheritance. TimedDoor can inherit from both Door and TimerClient. | |||
[[Image:Multiple.jpg |center|Multiple Inheritance]] | |||
The | The Disadvantages of "fat interface" can be alleviated by using Adapter pattern either through Delegation or Multiple inheritance. | ||
= Summary = | |||
The Interface Segregation Principle is very simple at heart and although it states something that would seem somewhat obvious, it is many times ignored. By abiding to ISP, we can improve the quality of our code by making sure that we not only comply with the exact requirements of an interface by implementing everything defined in the contract, but we also aim for reducing the responsibilities of a class by minimizing an interface, and thus complying with the Single Responsibility Principle.[1][2][3] | |||
[http:// | = References = | ||
1 [http://www.objectmentor.com/resources/articles/isp.pdf The Interface Segregation Principle, Engineering Notebook for C++, 1996] | |||
[http:// | 2 [http://en.wikipedia.org/wiki/Interface_segregation_principle Interface Segregation Principle, Retrieved April, 2010] | ||
[http://www. | 3 [http://www.rajivnarula.com/blog/2009/02/14/interface-segregation-principle-isp/ Interface Segregation Principle, Ravij Narula, 2010.] | ||
[http:// | 4 [http://download.oracle.com/javase/tutorial/java/concepts/interface.html What is an Interface? The Java Tutorials by Oracle, 2010] | ||
[http:// | 5 [http://www.oodesign.com/interface-segregation-principle.html Interface Segregation Principle, OOPDesign.com, 2009] | ||
[http:// | 6 [http://dotnetcenter.it/articles/10/SOLID-5-simple-principles-Interface-Segregation-Principle-Part-1.html Hariri, H. ,December 18, 2009] | ||
[http:// | 7 [http://martinfowler.com/bliki/RoleInterface.html Role Interface, Fowler Martin] |
Latest revision as of 18:41, 16 November 2010
Introduction
The Interface Segregation Principle (ISP) focuses on the cohesiveness of interfaces with respect to the clients that use them. ISP is very similar to high cohesion principle of GRASP. ISP helps developers to change, refactor and redeploy their code easily. This principle alleviates the disadvantages of "fat" or "polluted" interfaces. [1] ISP is considered as the eye of the SOLID design principle. Two main ISP guidelines are: Classes should not be forced to depend on methods that they do not use, and the dependency of one class to another one should depend on the smallest possible interface. [3][5]
Brief Introduction to Interfaces in OOP
In Object Oriented languages, an interface separates the implementation and defines the structure. Apart from that, an interface is very useful when the implementation changes frequently. Interface can be used to define a generic template and then one or more abstract classes to define partial implementations of the interface. Generally, interfaces are used as a group of related methods with empty bodies. Interfaces form a "contract" between the class and the outside world, and this contract is enforced at build time by the compiler. Interfaces are widely used in Object Oriented Languages such as Java,C# and C++. [4][7]
Fat Interfaces
As stated above, ISP is used to overcome the problems introduced by "fat interfaces". In order to clarify this term, consider the example given below. [6]
Car, Motorcycle and/or Aircraft classes implement the Abstract Vehicle interface that defines methods : TurnLeft, TurnRight, DriveForwards and DriveBackwards. All these methods are going to be used by the classes which implements this interface. There will not be any problems if Car class implements this interface, since every car turns left, turns right, drives forwards and drive backwards. Assume that Aircraft class also implements Vehicle Interface. Any aircraft can turn left, turn right and drive forwards. On the other hand, no aircraft can drive backwards by itself (without and help of a special helper). Another example: if a Motorcycle class implements the Vehicle abstract interface, it has to use DriveBackwards method, although it cannot drive backwards by itself. Here, The Abstract Vehicle Interface is an example of a "fat interface". One of the side-effects of fat interfaces is that any class that implements the interface ends up doing too many things and this can clearly violate the Single Responsibility Principle.
ISP for " Fat Interfaces "
By breaking interfaces down into smaller chunks, we potentially reduce the responsibilities of a class and thus provide higher cohesion between the methods of a particular interface. This also provides the benefit of making a clear statement to consumers of the interface of what minimum functionality is required to be implemented: everything. There uncertainty of whether a particular method or property needs to be implemented vanishes, reducing the factor of surprise. The Vehicle interface could be decomposed into ForwardMovingVehicle and BackwardMovingVehicle. If there are classes that require both functionalities, they would implement both interfaces. Alternatively, if only one interface were required, for example for Aircraft, then only the ForwardMovingVehicle interface would be implemented, avoiding giving way to empty declarations with NotImplementedException exceptions as their implementation. If we apply ISP to the above example, new "thin" interfaces would be like below.
Interface Pollution
Interface Pollution term is used interchangeable with Fat Interfaces. Whenever an interface is added to base class, that base class does not need, base class is polluted with that interface. In other words, base class' interface has been polluted. [1]
ISP in Action
Consider the following example in order to better understand The Interface Segregation Principle. A Security system includes Door objects which has the methods given below. Now, consider a Timer class which is used to sound an alarm when the door has been left open for too long. TimedDoor object communicates Timer class to do so.
Whenever an object wants to be informed about an timeout, it calls Register function of the Timer class. The problem is how can the TimerClient class communicate with the TimedDoor class? Common solution is inheriting from TimerClient class.
The Door class depends upon TimerClient, but not all types of Door need timing. Moreover, all the applications that use those derivatives will include TimerClass methods, even though they are not using them (Interface Pollution).
SInce Door and TimerClient represent interfaces for different clients. They should be separated.
Separation Through Delegation
Adapter pattern can be used to solve the problem above. The solution can be implemented by creating an adapter object that derives from TimerClient and delegates to TimedDoor. When the TimedDoor wants to register a timeout request with Timer, it creates a DoorTimerAdapter and registers with Timer class. If Timer sends the Timeout to DoorTimerAdapter, it delegates that message back to the TimedDoor.
The Interface Segregation Principle has been applied above. By doing so, the coupling of Door clients to Timer has been prevented. Even if Timer is changed, Door objects will not be affected.
Separation Through Multiple Inheritance
If the language developer uses supports Multiple Inheritance, the Interface Segregation Principle can be applied through multiple inheritance. TimedDoor can inherit from both Door and TimerClient.
The Disadvantages of "fat interface" can be alleviated by using Adapter pattern either through Delegation or Multiple inheritance.
Summary
The Interface Segregation Principle is very simple at heart and although it states something that would seem somewhat obvious, it is many times ignored. By abiding to ISP, we can improve the quality of our code by making sure that we not only comply with the exact requirements of an interface by implementing everything defined in the contract, but we also aim for reducing the responsibilities of a class by minimizing an interface, and thus complying with the Single Responsibility Principle.[1][2][3]
References
1 The Interface Segregation Principle, Engineering Notebook for C++, 1996
2 Interface Segregation Principle, Retrieved April, 2010
3 Interface Segregation Principle, Ravij Narula, 2010.
4 What is an Interface? The Java Tutorials by Oracle, 2010
5 Interface Segregation Principle, OOPDesign.com, 2009