Let’s go through an example to understand this principle.
Let’s say OPS class has three operations op1, op2, and op3. And there are three users, User1 uses op1, User2 uses op2, User3 uses op3 . If there is change in op3, both User1 and User2 will have to recompile and redeploy their code.
Now instead if each of these operations are segregated into three different interfaces and each user just depends on their interface, then if there is change in op3, only user3 will need to recompile and redeploy their code. This is called Interface Segregation Principle.
ISP and Languages
In statically typed languages like Java, with statements like import, include, use, etc, create source code dependencies, that force recompilation and redeployment and so ISP becomes necessary.
In dynamically typed languages, where declarations does not exists, but inferred at runtime, there are no source code dependencies, that force recompilation and redeployment. This is primary reason systems with dynamically typed languages are more flexible and less tightly coupled.
ISP and Architecture
ISP is just not language level restriction. But it is also relevant at architecture level. It is harmful to depend on a module that contains more than you need.
For example, you are architecting a system, and you decide to use a framework that depends on a database. If there is change in the database, both the framework and your system would need to recompile and redeploy. Or if any feature in the database fails, it will call failure in both the framework and your system.
The lesson is depending on something that carries extra baggage that we don’t need can cause us trouble that we don’t expect.
Thanks for stopping by! I hope this gives a good preview into ISP. Eager to hear your thoughts and chat, please leave comments below and we can discuss.
Arrays class in Java has a sort method which takes in an array and returns the sorted array. It works well for arrays of primitive types like int, char, float, double, etc., and even for String. But returns an error when we want to sort an array of objects.
Comparable
Consider the following example: Suppose we have a Player class which stores the player’s name, age, weight and number of his/her wins.
/**
* Player --- store the players information
*/
class Player{
private String name;
private int age;
private int weight;
private int wins;
Player(String name, int age, int weight, int wins){
this.name = name;
this.age = age;
this.weight = weight;
this.wins = wins;
}
//Getter method for name
public String getName(){
return name;
}
//Setter method for name
public void setName(String n){
name = n;
}
//Getter method for age
public int getAge(){
return age;
}
//Setter method for age
public void setAge(int a){
age = a;
}
//Getter method for weight
public int getWeight(){
return weight;
}
//Setter method for weight
public void setWeight(int w){
weight = w;
}
//Getter method for wins
public int getWins(){
return wins;
}
//Setter method for wins
public void setWins(int wi){
wins = wi;
}
public String toString(){
String msg = name + " " + age + " " + weight + " " + wins;
return msg;
}
}
We want to sort an array of such players according to their names in ascending order. We can do this by using Arrays.sort(Object[] array) method.
public static void main(String[] args){
Player[] players = { new Player("John", 23, 45, 5),
new Player("Andy", 20, 55, 7),
new Player("Mani", 25, 47, 2),
new Player("Bob", 19, 49, 9),
new Player("Holly", 21, 50, 2)
};
Arrays.sort(players);
for(Player p: players)
System.out.println(p.toString());
}
But we receive an error when we run the above code:
Exception in thread "main" java.lang.ClassCastException: Player cannot be cast to java.lang.Comparable
at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:188)
at java.util.Arrays.sort(Arrays.java:1246)
at PlayerComparable.main(PlayerComparable.java:86)
This error occurred because we didn’t define the criteria according to which the objects must be sorted.
To sort objects, we have to compare them on the basis of their property. And to compare objects we need to make our object implement the Comparable interface and override its compare method.
Therefore, our class now implements the comparable interface and overrides the compare method which compares the name of the current object with the name of the passed object using the String’s compareTo method and returns the result accordingly.
class Player implements Comparable<Player>{
private String name;
private int age;
private int weight;
private int wins;
Player(String name, int age, int weight, int wins){
this.name = name;
this.age = age;
this.weight = weight;
this.wins = wins;
}
//Getter method for name
public String getName(){
return name;
}
//Setter method for name
public void setName(String n){
name = n;
}
//Getter method for age
public int getAge(){
return age;
}
//Setter method for age
public void setAge(int a){
age = a;
}
//Getter method for weight
public int getWeight(){
return weight;
}
//Setter method for weight
public void setWeight(int w){
weight = w;
}
//Getter method for wins
public int getWins(){
return wins;
}
//Setter method for wins
public void setWins(int wi){
wins = wi;
}
@Override
public int compareTo(Player p){
return name.compareTo(p.getName());
}
public String toString(){
String msg = name + " " + age + " " + weight + " " + wins;
return msg;
}
}
Now when we sort the array using Arrays.sort(players), the players are sorted in ascending order of their names:
Andy 20 55 7
Bob 19 49 9
Holly 21 50 2
John 23 45 5
Mani 25 47 2
Comparator
The comparable interface allows us to sort an object based on only one property. Another way to compare objects is to create a Comparator class using the Comparator interface. This method allows us to sort based on multiple properties of an object. So, using Comparator we can sort based on age, weight, and number of wins.
Suppose we want to sort the array on the basis of Player’s age. We can do that by creating a class AgeComparator which implements Comparator interface and overrides its compare method. In that method, we compare the ages of both objects and returns the result accordingly. Here I converted the primitive int values to Integer values and called the Integer’s compareTo method on them.
class AgeComparator implements Comparator<Player> {
@Override
public int compare(Player a, Player b){
return new Integer(a.getAge()).compareTo(new Integer(b.getAge()));
}
}
Player[] players = { new Player("John", 23, 45, 5),
new Player("Andy", 20, 55, 7),
new Player("John", 25, 47, 2),
new Player("Bob", 19, 49, 9),
new Player("Holly", 21, 50, 2)
};
Arrays.sort(players, new AgeComparator());
for(Player p: players)
System.out.println(p.toString());
Now we call Arrays.sort(array, comparator) method for the player’s array. This method now sorts the array based on ages of the players.
Bob 19 49 9
Andy 20 55 7
Holly 21 50 2
John 23 45 5
John 25 47 2
Similarly, we can write comparators to sort the array according to weight and wins. Example:
class WeightComparator implements Comparator<Player> {
@Override
public int compare(Player a, Player b){
return new Integer(a.getWeight()).compareTo(new Integer(b.getWeight()));
}
}
class WinsComparator implements Comparator<Player> {
@Override
public int compare(Player a, Player b){
return new Integer(a.getWins()).compareTo(new Integer(b.getWins()));
}
}
We can even sort on the basis of more than one property using the comparator. One example is to sort Players according to their names and wins. If names are same, we sort the objects in decreasing order of their wins. We can do this by first comparing the string names of two players. If names are same then only we compare the wins of two players and return the result accordingly.
class NameWinsComparator implements Comparator<Player>{
@Override
public int compare(Player a, Player b){
String nameA = a.getName();
String nameB = b.getName();
if(nameA.equals(nameB))
return new Integer(b.getWins()).compareTo(new Integer(a.getWins()));
else
return nameA.compareTo(nameB);
}
}
The output for the player’s array is:
Andy 20 55 7
Bob 19 49 9
Holly 21 50 2
John 23 45 5
John 25 47 2
Here the last two elements have the same name John and they are sorted according to their wins in decreasing order.