Design Patterns_Behavioral Patterns - "Observer Patterns"
Les notes sont organisées à partir de l'explication détaillée des modèles de conception Java par les programmeurs Dark Horse, 23 modèles de conception Java (diagramme + analyse du code source du framework + combat réel)
aperçu
définition
- Le mode observateur, également connu sous le nom de mode publication-abonnement (Publier / S'abonner), définit une relation de dépendance un-à-plusieurs, permettant à plusieurs objets observateur d'écouter un objet sujet en même temps. L'objet sujet informe tous les objets observateurs des changements d'état, leur permettant de se mettre à jour automatiquement.
structure
Le modèle d'observateur a les rôles suivants :
- Sujet : sujet abstrait (abstrait observé), le rôle de sujet abstrait enregistre tous les objets observateurs dans une collection, chaque sujet peut avoir n'importe quel nombre d'observateurs, le sujet abstrait fournit une interface, vous pouvez ajouter et supprimer des objets observateurs .
- ConcreteSubject : sujet spécifique (observateur spécifique), ce rôle stocke l'état pertinent dans l'objet observateur spécifique et envoie une notification à tous les observateurs enregistrés lorsque l'état interne du sujet spécifique change.
- Observer : Abstract observer est une classe abstraite d'observateur, qui définit une interface de mise à jour, de sorte qu'il se met à jour lorsqu'il est informé des changements de thème.
- ConcrereObserver : Observateur concret, qui implémente l'interface de mise à jour définie par l'observateur abstrait, afin de mettre à jour son propre état lorsqu'il est notifié des changements de sujet.
Réalisation de cas
[Exemple] Compte officiel WeChat
Lorsque vous utilisez le compte officiel WeChat, tout le monde vivra une telle expérience. Lorsqu'il y a une nouvelle mise à jour de contenu dans le compte officiel que vous suivez, elle sera transmise au client WeChat qui suit le compte officiel. Nous utilisons le mode observateur pour simuler un tel scénario. L'utilisateur de WeChat est l'observateur et le compte officiel de WeChat est l'observé (rôle de sujet). Plusieurs utilisateurs de WeChat suivent le compte officiel de Program Ape.
Le diagramme de classes est le suivant :
![](https://pic-oss1.oss-cn-beijing.aliyuncs.com/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F.png#pic_center)
code afficher comme ci-dessous:
-
Classe abstraite d'observateur, qui définit une méthode mise à jour
public interface Observer { void update(String message); }
-
La classe d'observateur spécifique, les utilisateurs de WeChat sont des observateurs, qui implémente la méthode de mise à jour
public class WeixinUser implements Observer { // 微信用户名 private String name; public WeixinUser(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name + "-" + message); } }
-
Classe de sujet abstraite (observée), qui fournit trois méthodes d'attachement, de détachement et de notification
public interface Subject { // 增加订阅者(观察者对象) public void attach(Observer observer); // 删除订阅者(观察者对象) public void detach(Observer observer); // 通知订阅者更新消息 public void notify(String message); }
-
Le compte public WeChat est une classe de sujet spécifique (en particulier l'observateur), qui stocke les utilisateurs de WeChat qui s'abonnent au compte public et implémente les méthodes dans le sujet abstrait
public class SubscriptionSubject implements Subject { // 储存订阅公众号的微信用户 private List<Observer> weixinUserlist = new ArrayList<Observer>(); @Override public void attach(Observer observer) { weixinUserlist.add(observer); } @Override public void detach(Observer observer) { weixinUserlist.remove(observer); } @Override public void notify(String message) { for (Observer observer : weixinUserlist) { observer.update(message); } } }
-
programme client
public class Client { public static void main(String[] args) { // 1.创建公众号对象 SubscriptionSubject mSubscriptionSubject = new SubscriptionSubject(); // 2.创建微信用户 WeiXinUser user1 = new WeiXinUser("孙悟空"); WeiXinUser user2 = new WeiXinUser("猪悟能"); WeiXinUser user3 = new WeiXinUser("沙悟净"); // 3.订阅公众号 mSubscriptionSubject.attach(user1); mSubscriptionSubject.attach(user2); mSubscriptionSubject.attach(user3); // 4.公众号更新发出消息给订阅的微信用户 mSubscriptionSubject.notify("传智黑马的专栏更新了"); } }
sortir
孙悟空-传智黑马的专栏更新了 猪悟能-传智黑马的专栏更新了 沙悟净-传智黑马的专栏更新了
Avantages et inconvénients
avantage
- La relation de couplage entre la cible et l'observateur est réduite, et il existe une relation de couplage abstraite entre les deux.
- La personne observée envoie une notification, et tous les observateurs enregistrés recevront l'information [Le mécanisme de diffusion peut être réalisé]
défaut
- S'il y a beaucoup d'observateurs, il faudra du temps pour que tous les observateurs reçoivent les notifications des observateurs.
- Si l'observateur a une dépendance circulaire, la notification envoyée par l'observateur entraînera l'appel circulaire de l'observateur, ce qui entraînera le plantage du système
scènes à utiliser
- Il existe une relation un-à-plusieurs entre les objets, et les changements d'état d'un objet affecteront les autres objets.
- Lorsqu'un modèle abstrait a deux aspects, dont l'un dépend de l'autre.
Implémentation fournie dans JDK - Observable/Observer
En Java, les modèles d'observateur sont définis par java.util.Observable(抽象主题角色类)
et java.util.Observer(抽象观察角色接口)
, tant que leurs sous-classes sont implémentées, des instances de modèle d'observateur peuvent être écrites.
Classe observable
La classe Observable est une classe cible abstraite (observée), qui a une variable membre de collection Vector pour stocker tous les objets observateurs à notifier.
private Vector<Observer> obs;
// 在无参构造方法中赋值
public Observable() {
obs = new Vector<>();
}
Présentons ses trois méthodes les plus importantes.
-
void addObserver(Observer o)
Méthode : utilisée pour ajouter un nouvel objet observateur à la collection.public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); // 如果不存在则添加到集合中 if (!obs.contains(o)) { obs.addElement(o); } }
-
void notifyObservers(Object arg)
Méthode : appelez la méthode de mise à jour de tous les objets d'observation de la collection pour les notifier des modifications de données. Habituellement, les observateurs qui ont rejoint l'ensemble plus tard seront informés plus tôt.public void notifyObservers() { notifyObservers(null); } || \/ public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { // 只有changed为true才可以执行到下面的for循环 if (!changed) return; // 集合转数组 arrLocal = obs.toArray(); // 这个方法会将changed置为false 因为即将进行通知 clearChanged(); } // 倒序遍历数组 所以这就是为什么越晚加入集合的观察者越先得到通知 for (int i = arrLocal.length-1; i>=0; i--) // 逐一通知观察者(调用update方法) ((Observer)arrLocal[i]).update(this, arg); }
-
void setChange()
Méthode : Elle permet de positionner un drapeau interne de type booléen, indiquant que l'objet cible a changé. notifyObservers() ne notifiera les observateurs que si c'est vrai.protected synchronized void setChanged() { changed = true; }
Interface observateur
L'interface Observer est un observateur abstrait qui surveille les changements dans l'objet cible. Lorsque l'objet cible change, l'observateur est averti et appelle la méthode de mise à jour pour effectuer le travail correspondant.
【Exemple】La police a attrapé un voleur
Le modèle d'observateur peut également être utilisé par la police pour attraper le voleur. La police est l'observateur et le voleur est l'observé. code afficher comme ci-dessous:
-
Le voleur est un observateur, il doit donc hériter de la classe Observable
public class Thief extends Observable { private String name; public Thief(String name) { this.name = name; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void steal() { System.out.println("小偷:我偷东西了,有没有人来抓我!!!"); super.setChanged(); // changed = true,调用通知的方法 才会执行观察者的update方法 super.notifyObservers(); } }
-
La police est un observateur, elle doit donc implémenter l'interface Observer
public class Policemen implements Observer { private String name; public Policemen(String name) { this.name = name; } public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public void update(Observable o, Object arg) { System.out.println(this.getName() + "警察:" + ((Thief) o).getName() + ",我已经盯你很久了,你可以保持沉默,但你所说的将成为呈堂证供!!!"); } }
-
code client
public class Client { public static void main(String[] args) { // 创建小偷对象 Thief t = new Thief("隔壁老王"); // 创建警察对象 Policemen p = new Policemen("小李"); // 让警察盯着小偷(订阅) t.addObserver(p); // 小偷偷东西(发布) t.steal(); } }
sortir
小偷:我偷东西了,有没有人来抓我!!! 小李警察:隔壁老王,我已经盯你很久了,你可以保持沉默,但你所说的将成为呈堂证供!!!