How to understand the principle of interface isolation
Robert Martin defines it in the SOLID principle: "Clients should not be forced to depend upon interfaces that they do not use.". The "client" can be understood as the caller or user of the interface.
To understand the interface isolation principle of love and marriage app source code, the focus is on how to understand the "interface", which can be started from the following aspects:
- A set of API interfaces
- Single API interface or function
A set of API interfaces as "interfaces"
Now we have a set of interfaces related to account, which are provided to the background query account system call of the marriage app source code, including obtaining account id, account name and account amount. See the following examples for details:
public interface AccountService { String getAccountId(); String getAccountName(); long getMoney(); } public class AccountServiceImpl implements AccountService { public String getAccountId() {...} public String getAccountName() {...} public long getMoney() {...} }
At this time, the background management account system of the marriage app source code needs to increase or decrease the account amount. I hope the account system can provide corresponding interfaces.
At this time, what do we need to do? You may directly add addMoney(long) and deductMoney(long) methods to the AccountService. The function is implemented and solved, but it will dig holes for careless little partners here.
Why are there pits here? The increase or decrease of the amount of the source code account of love and marriage app is a very important operation. Our expectation is that the increase or decrease of the amount is only provided to the background management account system, and other systems cannot call it. Otherwise, one day, the little partner's hand will shake and the pit will be big. From the perspective of the source code service architecture of love and marriage app, the interface call can be limited through interface authentication to prevent misoperation of account amount.
Better implementation scheme: according to the principle of interface isolation, the ISP and love app source code client should not be forced to rely on the interface it does not need. The interface for increasing or decreasing the account amount needs to be separately placed in another interface LimitedAccountService class. The interface is only provided for the background management account system call, and other systems only provide the AccountService interface. Specific implementation:
public interface LimitedAccountService { void addMoney(long money); void deductMoney(long money); } public class LimitedAccountServiceImpl implements LimitedAccountService { public void addMoney(long money) {...} public void deductMoney(long money) {...} }
When designing microservices or class library interfaces, if some interfaces are only used by some callers, we need to isolate these interfaces and use them separately for the corresponding callers, rather than forcing other callers to rely on the interfaces that will not be used.
A single API interface or function as an interface
We use another perspective to understand "interface", which is understood as a single API interface or function (for convenience of subsequent description, referred to as "function"). For functions, the understanding of interfaces is that functions should be designed with a single function, and multiple different functional logics should not be implemented in one function.. Next, let's take a look at an example:
// Player information statistics BO class public class UserStatistics { private int maxLevel; private int minLevel; private int averageScore; // getter and setter } public UserStatistics calculate(List<User> users) { UserStatistics userStatistics = new UserStatistics(); // Statistics player information return userStatistics; }
The method calculate includes the calculation of the highest level, the lowest level and the average score, and the responsibility is not single enough. Of course, judging whether the function has a single responsibility also has subjective factors and scene factors. Imagine that in some cases, only the highest level maxLevel and the lowest level minLevel need to be used in the source code of marriage app. In other cases, only the average score is used. If we call the function calculate every time, we will calculate all the information, which will cause a lot of useless work and waste CPU resources. If we have a large amount of data, it will lead to great performance pressure on the system.
In this scenario, the design of function calculate is unreasonable. Let's change the implementation method:
public int calculateMaxLevel(List<User> users) {...} public int calculateMinLevel(List<User> users) {...} public int calculateAverageScore(List<User> users) {...}
In the second implementation, we split the function calculate into multiple interface implementations and call them on demand to solve the problems mentioned above.
Here, you may wonder how the interface isolation principle is so similar to a single responsibility? In fact, the two principles focus on different points. The single responsibility focuses on the design of the source code module, class and interface of the marriage app; The principle of interface isolation focuses on the design of the source code interface of love and marriage app. The caller only uses some interfaces or some functions of the interface. We can all think that the design of the interface is not single enough.