Skip to content
Advertisement

Applying Interface Segregation Principle to service layer interface

Using the book as analogy, suppose I have a book resource with the following API (there are also update and delete etc but for simplicity only show two here)

GET /book/{id}
POST /book

Each of these API would call other APIs to get the result, rather than the typical CRUD database operation. And based on the requirement / existing framework constraint, there are separate two controller class GetBookController and CreateBookController. The controller is to handle the request and response. So the actual business logic and retrieve / create book are in the service layer.

The question then is, should there be a separate interface for each of book operation(GetBookService and CreateBookService), or to have just only one (BookService)?

Based on the Interface Segregation Principle which states “Clients should not be forced to depend upon interfaces that they do not use”. Here the GetBookController class is the client, where it only has to query book without creating it, so it only requires GetBookService. If it is to use BookService, it doesn’t use the method createBook, which seems to violate ISP principle. However, if using separate interface, it would result in many interface and implementation classes being created. Am I misunderstanding the ISP principle?

@Controller
public class GetBookController {
    
    @Autowired
    private GetBookService getBookService;
}

@Controller
public class CreateBookController {
    
    @Autowired
    private CreateBookService createBookService;
}

public interface GetBookService {
    Book getBook(long id);
}

public interface CreateBookService {
    Boolean createBook(Book request);
}

public interface BookService {
    Book getBook(long id);
    Boolean createBook(Book request);
}

Advertisement

Answer

it would result in many interface and implementation classes being created

Yeah, you are right

The question then is, should there be a separate interface for each of book operation(GetBookService and CreateBookService), or to have just only one (BookService)?

ISP is how interface can be consumed. So, whether it is necessary to consume other methods of interface or don’t depend on more than you need.

An example with HDD that uses ISP:

public interface IReadable
{
    string Read();
}

public interface IWriteable
{
    void Write();
}

public class HDD : IReadable, IWriteable
{
    public string Read() { }

    public void Write()  { }
}

By creating one interface for Read() and Write() methods, it would obligate class to implement both methods in class. But some classes only want to read data, others want to write data, and some to do both. E.g. card reader might want to read data. So in this case it is better to create separate interfaces.

So let’s look another example with CardReader. CardReader just reads data, it does not write data. So, if we inherit one interface with Read() and Write() methods, then we would violate ISP principle. An example of violation of ISP:

public interface IWriteReadable
{
    string Read();
    void Write();
}

public class CardReader : IWriteReadable
{
    // this is a necessary method
    public string Read() { }

    // here we are obligating to implement unnecessary method of interface
    public void Write() { }
}

So by applying ISP, you only puts methods in interface that are necessary for the client class. If your class/client just wants to read data, then you need to use IReadable interface, not IReadableWriteable.

And in my view and like an reply suggested, it is better to create one controller for book. It might be okay to have separate controllers for Read and Create actions if there are many variations of these methods and controller became very big.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement