Что такое интерфейс компонента
Интерфейс компонента — это описание всех операций, предоставляемых компонентом. Интерфейс компонента — это множество операций, доступных через фасад компонента. Фасад компонента — это корень интерфейса.
Концептуально компонент можно выразить формулой:
Component exposes Interface
Component.start() → Facade
Facade provides access to Interface
Выражение Component exposes Interface означает, что компонент предоставляет описание доступных операций, например, в виде набора классов или HTTP-точек. Component.start() → Facade говорит, что фасад становится доступен только после вызова точки запуска, а Facade provides access to Interface — что именно через фасад доступны все объявленные операции.
Интерфейс компонента может быть описан разными языками. В модульном монолите он выражается сигнатурами Java-методов, а в распределённой системе — описаниями HTTP-эндпоинтов, определениями RPC-вызовов и т. п.
Границы интерфейса компонента определяются тем, какие операции доступны клиенту через фасад. На языке Java это будут все поля и методы, до которых можно добраться от фасада по цепочкам вызовов, а также конструкторы тех классов, объекты которых эти методы принимают в качестве аргументов. Те поля и методы, которые в этих цепочках не участвуют, в интерфейс не входят. Поясним это на примере программы карточной игры «21»[*]:
Предположим, взаимодействие компонентов, клиента и сервера, будет организовано через RMI-протокол.
public interface Table extends Remote {
Player sitDown() throws RemoteException;
}
public interface Player extends Remote {
int drawNextCard() throws RemoteException;
void passTurn() throws RemoteException;
}
public class RegularTable extends UnicastRemoteObject implements Table {
private final List<RegularPlayer> players = new ArrayList<>();
private final Deck deck = new Deck();
private int turn = 0;
public RegularTable() throws RemoteException {}
public Player sitDown() throws RemoteException {
var player = new RegularPlayer(this, deck);
players.add(player);
return player;
}
boolean isTurnOf(RegularPlayer p) {
return turn < players.size() && players.get(turn) == p;
}
void passTurn(RegularPlayer p) {
if (isTurnOf(p)) turn++;
}
}
public class RegularPlayer extends UnicastRemoteObject implements Player {
private final RegularTable table;
private final Deck deck;
private int sum = 0;
public RegularPlayer(RegularTable table, Deck deck) throws RemoteException {
this.table = table;
this.deck = deck;
}
public int drawNextCard() {
if (!table.isTurnOf(this)) {
throw new IllegalStateException("Not your turn.");
}
return sum += deck.draw().rank();
}
public void passTurn() {
table.passTurn(this);
}
}
public class Deck {
public Card draw() { ... }
}
public class Card {
public int rank() { ... }
}
Java-интерфейс Table является одновременно и фасадом, поскольку именно через него происходит вход в интерфейс компонента, и составляющей частью интерфейса компонента, поскольку объявляет метод sitDown. Возвращаемый методом sitDown объект типа Player открывает доступ к drawNextCard и passTurn, поэтому эти методы также входят в интерфейс компонента. Метод Deck.draw, хотя и объявлен как публичный, в интерфейс компонента не входит, поскольку он не доступен через фасад.
[*] «21»: каждый игрок одну за другой берёт карты из колоды и складывает их номиналы. Можно остановиться в любой момент. Выигрывает игрок, набравший наибольшую сумму, не превысившую 21.