Моделът на наблюдателя в Java

1. Общ преглед

В тази статия ще опишем модела на Observer и ще разгледаме няколко алтернативи за внедряване на Java.

2. Какъв е моделът на наблюдателя?

Наблюдателят е модел на поведенчески дизайн. Той определя комуникацията между обекти: наблюдаем и наблюдатели . Един видимо е обект, който не уведоми наблюдатели за промените в състоянието му.

Например, информационна агенция може да уведомява канали, когато получава новини. Получаването на новини е това, което променя състоянието на информационната агенция и води до уведомяване на каналите.

Нека да видим как можем сами да го приложим.

Първо, нека дефинираме класа NewsAgency :

public class NewsAgency { private String news; private List channels = new ArrayList(); public void addObserver(Channel channel) { this.channels.add(channel); } public void removeObserver(Channel channel) { this.channels.remove(channel); } public void setNews(String news) { this.news = news; for (Channel channel : this.channels) { channel.update(this.news); } } }

NewsAgency се наблюдава и когато новините се актуализират, състоянието на NewsAgency се променя. Когато се случи промяната, NewsAgency уведомява наблюдателите за този факт, като извиква техния метод update () .

За да може да направи това, наблюдаваният обект трябва да запази препратки към наблюдателите и в нашия случай това е променливата на каналите .

Нека сега видим как наблюдателя , на Канал клас, може да изглежда. Той трябва да има метода update () , който се извиква, когато състоянието на NewsAgency се промени:

public class NewsChannel implements Channel { private String news; @Override public void update(Object news) { this.setNews((String) news); } }

Интерфейсът на канала има само един метод:

public interface Channel { public void update(Object o); }

Сега, ако добавим инстанция на NewsChannel към списъка на наблюдатели , и променя състоянието на NewsAgency , копието NewsChannel ще се актуализира:

NewsAgency observable = new NewsAgency(); NewsChannel observer = new NewsChannel(); observable.addObserver(observer); observable.setNews("news"); assertEquals(observer.getNews(), "news");

Има предварително определен интерфейс на Observer в основните библиотеки на Java, което прави внедряването на модела на наблюдател още по-просто. Нека да го разгледаме.

3. Внедряване с наблюдател

Интерфейсът java.util.Observer дефинира метода update () , така че няма нужда да го дефинираме сами, както направихме в предишния раздел.

Нека да видим как можем да го използваме в нашата реализация:

public class ONewsChannel implements Observer { private String news; @Override public void update(Observable o, Object news) { this.setNews((String) news); } } 

Тук вторият аргумент идва от Observable, както ще видим по-долу.

За да дефинираме наблюдаемото , трябва да разширим Observable класа на Java :

public class ONewsAgency extends Observable { private String news; public void setNews(String news) { this.news = news; setChanged(); notifyObservers(news); } }

Имайте предвид, че не е нужно да извикваме директно метода update () на наблюдателя . Ние просто се обадете setChanged () и notifyObservers () , и видими класа прави останалата част за нас.

Също така, той съдържа списък с наблюдатели и излага методи за поддържане на този списък - addObserver () и deleteObserver ().

За да тестваме резултата, просто трябва да добавим наблюдателя към този списък и да зададем новината:

ONewsAgency observable = new ONewsAgency(); ONewsChannel observer = new ONewsChannel(); observable.addObserver(observer); observable.setNews("news"); assertEquals(observer.getNews(), "news");

Интерфейсът на Observer не е перфектен и е остарял от Java 9. Един от недостатъците му е, че Observable не е интерфейс, а клас, поради което подкласовете не могат да се използват като наблюдаеми.

Също така, разработчикът може да замени някои от синхронизираните методи на Observable и да наруши тяхната безопасност на нишките.

Нека да разгледаме интерфейса ProperyChangeListener , който се препоръчва вместо да се използва Observer .

4. Внедряване с PropertyChangeListener

В тази реализация наблюдаемият трябва да поддържа препратка към екземпляра PropertyChangeSupport . Помага да се изпращат известията до наблюдатели, когато се променя свойство на класа.

Нека дефинираме наблюдаемото:

public class PCLNewsAgency { private String news; private PropertyChangeSupport support; public PCLNewsAgency() { support = new PropertyChangeSupport(this); } public void addPropertyChangeListener(PropertyChangeListener pcl) { support.addPropertyChangeListener(pcl); } public void removePropertyChangeListener(PropertyChangeListener pcl) { support.removePropertyChangeListener(pcl); } public void setNews(String value) { support.firePropertyChange("news", this.news, value); this.news = value; } }

Използвайки тази поддръжка , можем да добавяме и премахваме наблюдатели и да ги уведомяваме, когато състоянието на наблюдаемото се промени:

support.firePropertyChange("news", this.news, value);

Тук първият аргумент е името на наблюдаваното свойство. Вторият и третият аргумент са съответно неговата стара и нова стойност.

Наблюдателите трябва да внедрят PropertyChangeListener :

public class PCLNewsChannel implements PropertyChangeListener { private String news; public void propertyChange(PropertyChangeEvent evt) { this.setNews((String) evt.getNewValue()); } }

Поради клас PropertyChangeSupport, който прави окабеляването вместо нас, можем да възстановим новата стойност на свойството от събитието.

Нека тестваме изпълнението, за да сме сигурни, че то също работи:

PCLNewsAgency observable = new PCLNewsAgency(); PCLNewsChannel observer = new PCLNewsChannel(); observable.addPropertyChangeListener(observer); observable.setNews("news"); assertEquals(observer.getNews(), "news");

5. Заключение

В тази статия разгледахме два начина за внедряване на шаблона за дизайн на Observer в Java, като се предпочита подходът PropertyChangeListener .

Изходният код на статията е достъпен в GitHub.