Skip to content

Latest commit

 

History

History
140 lines (107 loc) · 5.08 KB

8. Interface Segregation Principle - ISP.MD

File metadata and controls

140 lines (107 loc) · 5.08 KB

Interface Segregation Principle

  • No clients should be forced to depend on methods they do not use.
  • This often becomes a problem when clients have dependencies on what we call those fat classes (classes that have too many responsibilities)
  • Having an interface to separate behavior is a good idea, and it prevents tight coupling between between the objects.

Example

Diagram A (Bad Design)

image

  • In this logic, what if the Substitude Teacher is not allowed to teach (maybe monitoring students are their responsibility) . Teaching in this case is the responsibility of the main teacher.

  • In this case, a violation of the Interface Segregation Principle would be to have a substitute teacher or inherit from the teacher class because as as as for our definition, which means the SubstituteTeacher also have to implement the teach() method (like the diagram below). However in our logic, Substitute teachers don't actually teach. So this does not fall into this particular hierarchy because it is not really a teacher as per our definition.

We can however handle this probem by throwing a customer CannotTeachException. So we're actually throwing this cannot teach exception in the body of the teach method like so.

public class CannotTeachException extends Exception {
    
}
public class SubstitudeTeacher extends Teacher {
    @Override
    public void teach() {
        throw new CannotTeachException();
    }
}

This is BAD because we have to add the exception to the teacher class like so.

public abstract class Teacher {
    public abstract void teach() throw CannotTeachException; // <- Forcing changes on parent class by having to add an exception here
    
    private void makeAnnoucements() {
        ...
    }
    
    ...
    
    public void performOtherResponsibilites() {
        makeAnnoucements();
        takeAttendence();
        ...
    }
    
}
  • Now notice how the subclass is forcing change in its parent. Now in the definition of this abstract method we would actually have to throw the new exception. So this is unacceptable we should never force upon a parent class changes because things don't work out in the subclasses
  • Throwing an exception like this is an Anti-Pattern.

Solution

Diagram B (Good Design)

image

Italic font for abstraction
  • The solution to this whole mess would be to pull out a substitute teacher from this inheritance relationship because it simply is not a teacher as per our definition of what a teacher what a real teacher whose behavior should be.
  • We broken out the responsibility of teaching to a particular interface called CourseInstructor and the general responsibilities that all high school staff members should have is encapsulated in the SchoolStaff abstract class.

In this school staff abstract class:

public class SchoolStaff extends Employ {
    private void makeAnnouncements() {
        System.out.println("made announcements..");
    }
    private void takeAttendence() {
        System.out.println("took attendence..");
    }
    private void collectPaperWork() {
        System.out.println("collected paperwork..");
    }
    private void conductHallwayDuties() {
        System.out.println("conducted hallway duties..");
    }

    public void performOtherResponsibilities() {
        makeAnnouncements();
        takeAttendence();
        collectPaperWork();
        conductHallwayDuties();;
    }
}
public interface CourseInstructor {
    public void teach();
}
public class EnglishTeacher extends SchoolStaff implements CourseInstructor {

    @Override
    public void teach() {
        System.out.println("Taught English");
    }
}
public class MathTeacher extends SchoolStaff implements CourseInstructor {

    @Override
    public void teach() {
        System.out.println("Taught Math");
    }
}
public class ScienceTeacher extends SchoolStaff implements CourseInstructor {

    @Override
    public void teach() {
        System.out.println("taught science");
    }
}
public class SubstituteTeacher extends SchoolStaff {

}

Take-away

Interface Segregation Principle is all about segregating interfaces and make them smaller. Whenever you have an Interface, you need everything that implements that Interface to use every portion of the Interface.

You know when you are violating ISP, when a method is not meant to be called on an Object. In our example a SubstituteTeacher was not really a teacher so it didn't make sense for us to be calling the teach() method on that object.

Eg.

  • It doensn't make sense for a Turret Object to be able to access methods such as move even though move could be left unimplemented in the turret Object. Hence, the Turret Object should only inherit the GameObject interface, and not inherit the Moveable interface.