Simply put, this means, a client should not depend on something it doesn't need.
Ways to identify if you're violating Interface Segregation Principle:
- Too many functions in an interface
- Empty implementation, or simply throwing exceptions
- A class is implementing methods that are not needed
If a client only needs part of the interface, it still ends up depending on everything. Here's an example:
Let's say, you have an interactor that will let you know what screen you should show to the user. You will show the Home screen if user is already logged in, if not, you will show an Onboarding screen of you app.
Here's a simple diagram:
We have an InitialScreenInteractor depending on UserRepositoryProtocol (or Interface). And our UserRepository which implements UserRepositoryProtocol depends on UserDao (DAO - Data Access Object) and UserService (API).
In this example, the interactor only needs to know if there's a user. But given this setup, the InitialScreenInteractor ended up depending on everything - it is indirectly depending on UserDao and UserService, too. Even though it doesn't need the UserService.
Now, if we are going to test our interactor, we will be forced to implement the other two methods (saveUser and uploadAvatar) that we don't really needed.
class InitialScreenInteractorTests: XCTestCase {
private var sut: InitialScreenInteractor
override func setUpWithError() throws {
let repoMock = UserRepositoryMock()
sut = InitialScreenInteractor(userRepo: repoMock)
}
private class UserRepositoryMock: UserRepositoryProtocol {
func getUser() -> User? {
return User()
}
// Not Needed
func saveUser() -> Completable
func uploadAvatar(image: Data) -> Completable
}
}
With Interface Segregation Principle, we'll gonna have to create a different interface for getting the user.
Now, if we're going to test our interactor, we no longer need to implement methods we don't need.
class InitialScreenInteractorTests: XCTestCase {
private var sut: InitialScreenInteractor
override func setUpWithError() throws {
let repoMock = GetUserRepositoryMock()
sut = InitialScreenInteractor(userRepo: repoMock)
}
private class GetUserRepositoryMock: GetUserRepositoryProtocol {
func getUser() -> User? {
return User()
}
}
}
Comments