CSC/ECE 517 Fall 2010/ch6 6f ag: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 23: Line 23:
Designing software by adopting ISP will yield many simple interfaces that are more specific in nature which in turn will make the classes more cohesive.
Designing software by adopting ISP will yield many simple interfaces that are more specific in nature which in turn will make the classes more cohesive.
==How ISP can be implemented in the design==
==How ISP can be implemented in the design==
===#Segregation through Delegation===
===Segregation through Delegation===
The object form of the ADAPTER Pattern can be used to delegate the responsibility of implementing the thin interface to the class that is the client of the interface.
The object form of the ADAPTER Pattern can be used to delegate the responsibility of implementing the thin interface to the class that is the client of the interface.
===#Segregation through multiple inheritance===
===Segregation through multiple inheritance===
The methods that are to be included into the interfaces are grouped into interfaces such that all the methods in the interface are directed towards accomplishing a certain type of service. When a class has to use the methods in the interface, it has to implement the interface. When the class is required to implement methods from many interfaces, the class will have to inherit multiple light interfaces and also implement the methods in the interfaces.
The methods that are to be included into the interfaces are grouped into interfaces such that all the methods in the interface are directed towards accomplishing a certain type of service. When a class has to use the methods in the interface, it has to implement the interface. When the class is required to implement methods from many interfaces, the class will have to inherit multiple light interfaces and also implement the methods in the interfaces.


Line 32: Line 32:
Let us assume we have a student base class which other specialized student classes inherit from.
Let us assume we have a student base class which other specialized student classes inherit from.


A full time student at NCSU is allowed to register for a class. He can also choose to audit a particular class.
A full time student is allowed to register for a class. He can also choose to audit a particular class.


Lets say we have an interface called IEnroll.  
Lets say we have an interface called IEnroll.  
The IEnroll interface exposes two methods viz. registerClass() which should allow a student to register himself for a class, and auditClass() which allows a student to audit a class he has registered for.
The IEnroll interface exposes two methods viz. registerClass() which should allow a student to register himself for a class, and auditClass() which allows a student to audit a class he has registered for.
The FullStudent class is used to represent full time students. It extends the Student class and implements this IEnroll interface.
The FullStudent class is used to represent full time students. It extends the Student class and implements this IEnroll interface.
 
<br>
<table border=1>
<tr>[[Image:Figure 1Class diagram for FullStudent (violates ISP).png]]</tr>
</table>
  interface IEnroll {
  interface IEnroll {
     public void registerClass();
     public void registerClass();
Line 57: Line 60:
The PartStudent class represents the part time students. It extends the Student class.
The PartStudent class represents the part time students. It extends the Student class.
Now PartStudent class can either implement IEnroll to provide the registration facility. But in that case, PartStudent is forced to implement the auditClass method.
Now PartStudent class can either implement IEnroll to provide the registration facility. But in that case, PartStudent is forced to implement the auditClass method.
 
<table border=1>
<tr> [[Image:Figure 2Class diagram for PartStudent (violates ISP).png ]]</tr>
</table>
  class PartStudent extends Student implements IEnroll {
  class PartStudent extends Student implements IEnroll {
     public void registerClass()
     public void registerClass()
Line 76: Line 81:


We separate out the 2 functions into different interfaces now,
We separate out the 2 functions into different interfaces now,


  interface IRegisterClass {
  interface IRegisterClass {
Line 85: Line 91:


This allows the FullStudent and PartStudent to be defined as following:
This allows the FullStudent and PartStudent to be defined as following:
[[Image:Figure 3Class diagram for FullStudent (conforms to ISP).png]]


  class FullStudent extends Student implements IRegisterClass, IAuditClass
  class FullStudent extends Student implements IRegisterClass, IAuditClass
Line 97: Line 104:
     }
     }
  }
  }
[[Image:Figure 4Class diagram for PartStudent (conforms to ISP).png]]


  class PartStudent extends Student implements IRegisterClass
  class PartStudent extends Student implements IRegisterClass

Revision as of 18:49, 16 November 2010

Interface Segregation Principle

Introduction

Design phase is a very important phase in the entire process of [1] object-oriented software development. The need for a good design of software is to accommodate change into the software, a definite attribute of any software. For the benefit of the developers of these software, certain principles are laid out which ensure that the outcome of development phase is an easily manageable software rather than a rigid and fragile software. The principles of object-oriented software development are listed differently in different sources. The most commonly accepted and recognized is the [2]SOLID object oriented principles. In this article we focus on Interface segregation principle (ISP).

Interface Segregation Principle

Interface Segregation Principle emphasizes on

  • MANY CLIENT SPECIFIC INTERFACES ARE BETTER THAN ONE GENERAL PURPOSE INTERFACE

Implications of the emphasis

  1. The interfaces that are designed should not be fat, i.e the interface should not have too many methods which often do not get used together. The idea here is to avoid loading all the methods into a single interface, instead segregate the methods in the interface such that all the methods that contribute towards offering a single type of service (or single type of clients) are grouped under one single interface. Thereby dealing with a bulky interface that might be difficult to manage is avoided.
  2. The interface should be specific. The methods in the interface should be the ones that contribute towards offering only a specific type of service. For example, if there is an interface that offers methods that provide mathematical services to its clients, then the same interface should not contain methods that accomplish totally different types of tasks say, like a database functionality implementation. The main reason behind such interfaces being discouraged is that if a class decides to (or has to) implement that interface, then, it has to provide an implementation even for those methods that it doesn’t intend to use. Even though such implementations may be empty methods, it is not convenient and also distorts the readability of the code.

Results of following ISP

Designing software by adopting ISP will yield many simple interfaces that are more specific in nature which in turn will make the classes more cohesive.

How ISP can be implemented in the design

Segregation through Delegation

The object form of the ADAPTER Pattern can be used to delegate the responsibility of implementing the thin interface to the class that is the client of the interface.

Segregation through multiple inheritance

The methods that are to be included into the interfaces are grouped into interfaces such that all the methods in the interface are directed towards accomplishing a certain type of service. When a class has to use the methods in the interface, it has to implement the interface. When the class is required to implement methods from many interfaces, the class will have to inherit multiple light interfaces and also implement the methods in the interfaces.

Example

Consider an example of Course registration system which allows students to enroll in courses, similar to the one we have at NCSU. Let us assume we have a student base class which other specialized student classes inherit from.

A full time student is allowed to register for a class. He can also choose to audit a particular class.

Lets say we have an interface called IEnroll. The IEnroll interface exposes two methods viz. registerClass() which should allow a student to register himself for a class, and auditClass() which allows a student to audit a class he has registered for. The FullStudent class is used to represent full time students. It extends the Student class and implements this IEnroll interface.

interface IEnroll {
   public void registerClass();
   public void auditClass();
}
class FullStudent extends Student implements IEnroll {
   public void registerClass()
   {
       //allow a student to register for a particular class
   }
   public void auditClass()
   {
       //allow a student to audit an enrolled class
   }
}

Now lets suppose, NCSU decided not to allow part time students to audit a class once they have registered. The PartStudent class represents the part time students. It extends the Student class. Now PartStudent class can either implement IEnroll to provide the registration facility. But in that case, PartStudent is forced to implement the auditClass method.

class PartStudent extends Student implements IEnroll {
   public void registerClass()
   {
       //allow a student to register for a particular class
   }
   public void auditClass()
   {
       //do nothing since we didn't want this method in the first place!
   }
}

The other option is to define a new interface with just registClass method and use it in PartStudent class. But this defeats the purpose of having a common interface.

This is a good example of how our interface has become 'Fat' or 'Polluted'. It is exposing 2 different methods which its clients are forced to honor. This violates the ISP.

Lets see how we can correct this.

We separate out the 2 functions into different interfaces now,


interface IRegisterClass {
   public void registerClass();
}
interface IAuditClass {
   public auditClass();
}

This allows the FullStudent and PartStudent to be defined as following:

class FullStudent extends Student implements IRegisterClass, IAuditClass
{	
   public void registerClass()
   {
      //allow a student to register for a particular class
   }
   public void auditClass()
   {
      //allow a student to audit an enrolled class
   }
}

class PartStudent extends Student implements IRegisterClass
{
   public void registerClass()
   {
       //allow a student to register for a particular class
   }
}

This gives a clean and correct way in which the PartStudent class is not forced to depend on an interface it does not want.


Conclusion

Fat Interfaces are the interfaces that are not specific to a single client. Fat interfaces lead to unintended couplings between clients that ought otherwise to be isolated. By making use of the ADAPTER pattern, through multiple inheritance (class form), fat interfaces can be segregated into abstract base classes that resolve the unwanted coupling between clients. Thus maintaining loose coupling and high cohesion, which is an essential attribute of good software design.

See Also

  1. Design principles
  2. Three Sources of a Solid Object-Oriented Design
  3. Principles of OOD
  4. Hanselminutes episode on SOLID

External References

  1. The Interface Segregation Principle
  2. Design Principles and Design Patterns, Robert C Martin
  3. 2009 Gotham Ruby Conference, presentation on SOLID Object Oriented Design by Sandi Metz, Duke University.