Solid Principles
In this tutorial we are going to learn about the Interface Segregation Principle (ISP).
Reference
Interface Segregation Principle (ISP) states that a client must not be forced to implement an interface that it does not use and it must not be forced to depend on methods that it does not use.
In the following Java program we have the AllInOne interface that has print, scan, copy and fax capabilities. We also have HpAllInOne and CanonPrinter that implements the AllInOne interface. However, CanonPrinter can only perform printing operation therefore, rest of the methods are not implemented.
interface AllInOne {
public String print();
public String scan();
public String copy();
public String fax();
}
class HpAllInOne implements AllInOne {
@Override
public String print() {
return "Print done!";
}
@Override
public String scan() {
return "Scan done!";
}
@Override
public String copy() {
return "Copy done!";
}
@Override
public String fax() {
return "Fax done!";
}
}
class CanonPrinter implements AllInOne {
@Override
public String print() {
return "Print done!";
}
@Override
public String scan() {
// do nothing...
return null;
}
@Override
public String copy() {
// do nothing...
return null;
}
@Override
public String fax() {
// do nothing...
return null;
}
}
Test
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class ISPTests {
@Test
@DisplayName("Class that implements all the methods")
public void shouldNotVioletISP() {
HpAllInOne hpAllInOne = new HpAllInOne();
Assertions.assertEquals(hpAllInOne.print(), "Print done!");
Assertions.assertEquals(hpAllInOne.scan(), "Scan done!");
Assertions.assertEquals(hpAllInOne.copy(), "Copy done!");
Assertions.assertEquals(hpAllInOne.fax(), "Fax done!");
}
@Test
@DisplayName("Class that does not implements all the methods")
public void shouldVioletISP() {
CanonPrinter canonPrinter = new CanonPrinter();
Assertions.assertEquals(canonPrinter.print(), "Print done!");
Assertions.assertNull(canonPrinter.scan());
Assertions.assertNull(canonPrinter.copy());
Assertions.assertNull(canonPrinter.fax());
}
}
In the given example the CanonPrinter can only perform print operation however, it is forced to implement all the methods of the AllInOne interface.
Imagine someone looks at the CanonPrinter class and sees that it is implementing the AllInOne interface they will assume that the CanonPrinter must be able to perform scan operation. However, this is not the case and it would create a problem.
To solve this problem we can split the generic AllInOne interface into multiple specific interfaces and let the classes decide which interface to implement.
interface Print {
public String doPrint();
}
interface Scan {
public String doScan();
}
interface Copy {
public String doCopy();
}
interface Fax {
public String doFax();
}
class HpAllInOne implements Print, Scan, Copy, Fax {
@Override
public String doCopy() {
return "Copy done!";
}
@Override
public String doFax() {
return "Fax done!";
}
@Override
public String doPrint() {
return "Print done!";
}
@Override
public String doScan() {
return "Scan done!";
}
}
class CanonPrinter implements Print {
@Override
public String doPrint() {
return "Print done!";
}
}
Test
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class ISPTests {
@Test
@DisplayName("ISP testing")
public void shouldImplementOnlyTheRequiredInterfaces() {
HpAllInOne hpAllInOne = new HpAllInOne();
CanonPrinter canonPrinter = new CanonPrinter();
Assertions.assertNotNull(hpAllInOne.doPrint());
Assertions.assertNotNull(hpAllInOne.doScan());
Assertions.assertNotNull(hpAllInOne.doCopy());
Assertions.assertNotNull(hpAllInOne.doFax());
Assertions.assertNotNull(canonPrinter.doPrint());
}
}
ADVERTISEMENT