Интерфейсы полезны, когда у вас есть два класса, которые должны работать вместе, но должны быть максимально отделены друг от друга. Типичным примером этого является использование слушателей для соединения модели и вида вместе в шаблоне проектирования модель-представление-контроллер .
Например, допустим, у вас было приложение с графическим интерфейсом, в котором пользователи могли входить и выходить из системы. Когда пользователи выходят из системы, вы можете, скажем, изменить метку «В настоящий момент вошел в систему как« такой-то и такой-то »» и закрыть все видимые диалоговые окна.
Теперь у вас есть класс User
с методом logOut
, и всякий раз, когда вызывается logOut
, вы хотите, чтобы все это происходило. Один из способов сделать это - использовать метод logOut
для решения всех этих задач:
// Bad!
public void logOut() {
userNameLabel.setText("Nobody is logged in");
userProfileWindow.close();
}
Это не одобряется, потому что ваш класс User
теперь тесно связан с вашим графическим интерфейсом. Было бы лучше, если бы класс User
был тупее и не делал так много. Вместо того, чтобы закрывать userProfileWindow
, он должен просто сказать userProfileWindow
, что пользователь вышел из системы, и позволить userProfileWindow
делать все, что он хочет (он хочет закрыть себя).
Способ сделать это - создать общий интерфейс UserListener
с методом loggedOut
, который вызывается классом User
при выходе пользователя из системы. Любой, кто хочет знать, когда пользователь входит в систему и выходит из нее, затем реализует этот интерфейс.
public class User {
// We'll keep a list of people who want to be notified about logouts. We don't know
// who they are, and we don't care. Anybody who wants to be notified will be
// notified.
private static List<UserListener> listeners;
public void addListener(UserListener listener) {
listeners.add(listener);
}
// This will get called by... actually, the User class doesn't know who's calling
// this or why. It might be a MainMenu object because the user selected the Log Out
// option, or an InactivityTimer object that hasn't seen the mouse move in 15
// minutes, who knows?
public void logOut() {
// Do whatever internal bookkeeping needs to be done.
currentUser = null;
// Now that the user is logged out, let everyone know!
for (UserListener listener: listeners) {
listener.loggedOut(this);
}
}
}
// Anybody who cares about logouts will implement this interface and call
// User.addListener.
public interface UserListener {
// This is an abstract method. Each different type of listener will implement this
// method and do whatever it is they need to do when the user logs out.
void loggedOut(User user);
}
// Imagine this is a window that shows the user's name, password, e-mail address, etc.
// When the user logs out this window needs to take action, namely by closing itself so
// this information isn't viewable by other users. To get notified it implements the
// UserListener interface and registers itself with the User class. Now the User.logOut
// method will cause this window to close, even though the User.java source file has no
// mention whatsoever of UserProfileWindow.
public class UserProfileWindow implements UserListener {
public UserProfileWindow() {
// This is a good place to register ourselves as interested observers of logout
// events.
User.addListener(this);
}
// Here we provide our own implementation of the abstract loggedOut method.
public void loggedOut(User user) {
this.close();
}
}
Порядок действий будет выглядеть следующим образом:
- Приложение запускается, и пользователь входит в систему. Она открывает ее
UserProfileWindow
.
-
UserProfileWindow
добавляет себя как UserListener
.
- Пользователь бездействует и не касается клавиатуры или мыши в течение 15 минут.
- Воображаемый
InactivityTimer
класс уведомлений и звонков User.logOut
.
User.logOut
обновляет модель, очищая переменную currentUser
. Теперь, если кто-нибудь спросит, никто не вошел в систему.
User.logOut
проходит по списку слушателей, вызывая loggedOut()
для каждого слушателя.
- Вызывается метод
UserProfileWindow
*1055*, который закрывает окно.
Это здорово, потому что этот класс User
абсолютно ничего не знает о том, кому нужно знать о событиях выхода из системы. Он не знает, что метка имени пользователя должна быть обновлена, что окно профиля должно быть закрыто, ничего из этого. Если позже мы решим, что нужно выполнить больше действий, когда пользователь выходит из системы, класс User
вообще не нужно изменять.
Итак, шаблон слушателя является одним из примеров, где интерфейсы очень полезны. Все интерфейсы - это разделение классов, удаление связей и зависимостей между классами, которые должны взаимодействовать друг с другом, но не должны иметь прочных связей в своем коде друг с другом.