Vous souvenez-vous encore de la façon dont les gangsters ont coopéré dans le film de police et de gangster? Lorsqu'un gang est un cambriolage, une ou deux personnes prennent toujours le vent à la porte. S'il y a un mouvement, les complices à l'intérieur seront informés immédiatement pour se retirer de toute urgence. Peut-être que la personne qui fait la nouvelle ne connaît peut-être pas nécessairement chaque complice; Et il peut y avoir un nouveau frère cadet qui ne connaît pas celui qui laisse les nouvelles. Mais ce n'est rien, cela ne peut pas affecter leurs communications car ils ont un code qui a été convenu.
Haha, la relation entre le Venter et le voleur mentionné ci-dessus est un exemple vivant du modèle d'observateur en réalité.
Le mode observateur est également connu sous le nom de mode publication / abonnement. GOF définit le modèle d'observateur comme suit: définit une dépendance un-à-plusieurs entre les objets. Lorsque l'état d'un objet change, tous les objets qui en dépendent sont notifiés et mis à jour automatiquement.
Ici, je vais d'abord parler d'un principe important de la conception orientée objet - le principe de responsabilité unique. Par conséquent, chaque objet du système doit se concentrer sur des abstractions discrètes dans le domaine du problème. Par conséquent, idéalement, un objet ne fait qu'une seule chose. Cela apporte de nombreux avantages en développement: il offre une réutilisabilité et une maintenance, et est également une bonne base pour la refactorisation.
Par conséquent, presque tous les modèles de conception sont basés sur ce principe de conception de base. Je pense que l'origine du modèle d'observateur devrait être dans le traitement des données sur l'interface graphique et les données commerciales, car la plupart des exemples expliquant le modèle d'observateur sont maintenant ce sujet. Cependant, l'application du mode observateur n'est en aucun cas limitée à cet aspect.
Eh bien, la compréhension de la définition nécessite toujours des cas pour analyser. Les comptes de services WeChat sont très populaires de nos jours. Présentons le modèle d'observateur avec l'arrière-plan des comptes de service WeChat.
Regardez une image:
Chaque utilisateur a 3 lignes dans l'image ci-dessus, qui sont omises afin de rendre l'image claire.
Comme indiqué dans l'image ci-dessus, le numéro de service est notre thème et l'utilisateur est l'observateur. Maintenant, nous clarifions les fonctions suivantes:
1. Le compte de service est le thème, et les affaires poussent les messages
2. Les observateurs n'ont qu'à s'abonner au sujet, et ils seront envoyés dès qu'il y aura de nouvelles nouvelles.
3. Désibilisation lorsque vous ne voulez pas ce message de sujet
4. Tant que le compte de service est toujours là, quelqu'un sera abonné. Jetons maintenant un coup d'œil au diagramme de classe du modèle d'observateur:
Vient ensuite l'heure du code, nous simulons un compte de service de loterie WeChat 3D et certains abonnés.
Tout d'abord, commencez à écrire sur notre interface de sujet et notre interface d'observateur:
Package com.zhy.pattern.observer; / ** * L'interface de la rubrique, tous les sujets doivent implémenter cette interface * * @author zhy * * / Sujet de l'interface publique {/ ** * Enregistrer un observateur * * @param Observer * / public void registerObserver (Observer Observer); / ** * Supprimez un observateur * * @param observateur * / public void removeObserver (Observer Observer); / ** * Notifier tous les observateurs * / public void notifyObservers (); } package com.zhy.pern.observer; / ** * @author zhy Tous les observateurs doivent implémenter cette interface * / interface publique Observer {public void Update (String msg); }Classe d'implémentation du numéro de service 3D suivant:
Package com.zhy.pattern.observer; import java.util.arraylist; Importer java.util.list; classe publique ObjectFor3d implémente le sujet {private list <Bervever> Observers = new ArrayList <Bervever> (); / ** * Numéro de loterie 3D * / Private String msg; @Override public void RegisterObserver (Observer Observer) {Observers.Add (Observer); } @Override public void demoveObserver (Observer Observer) {int index = observateurs.indexof (Observer); if (index> = 0) {observateurs.Remove (index); }} @Override public void notifyObservers () {for (Observer Observer: observateurs) {Observer.update (msg); }} / ** * Message de mise à jour du sujet * * @param msg * / public void setmsg (String msg) {this.msg = msg; notifyObservers (); }}Simuler deux utilisateurs:
Package com.zhy.pattern.observer; classe publique Observer1 implémente l'observateur {sujet privé sujet; public Observer1 (sujet sujet) {this.subject = sujet; sujet.RegisterObserver (this); } @Override public void Update (String msg) {System.out.println ("Observer1 obtient le numéro 3D ->" + msg + ", je veux l'écrire."); }} Package com.zhy.pattern.observer; classe publique Observer2 implémente l'observateur {sujet privé sujet; Public Observer2 (sujet sujet) {this.subject = sujet; sujet.RegisterObserver (this); } @Override public void Update (String msg) {System.out.println ("Observer2 obtient le numéro 3D ->" + msg + "Je veux dire à mes colocataires."); }} On peut voir que tous les utilisateurs qui s'abonnent à des messages sont maintenus dans le compte de service, et tous les utilisateurs sont informés en cas de nouveau message dans le compte de service. L'architecture entière est un couplage lâche, et l'implémentation du thème ne dépend pas de l'utilisateur. Lorsqu'un nouvel utilisateur est ajouté, le code du thème n'a pas besoin d'être modifié; Comment l'utilisateur traite les données obtenues n'a rien à voir avec le thème;
Enfin, regardez le code de test:
package com.zhy.pattern.observer.test; import com.zhy.pattern.observer.objectfor3d; import com.zhy.pattern.observer.observer; import com.zhy.pattern.observer.observer1; import com.zhy.pattern.observer.observer2; import com.zhy.pattern.observer.Subject; Public Class Test {public static void main (String [] args) {// simule un numéro de service 3D objectfor3d sujectfor3d = new ObjectFor3d (); // Customer1 Observer Observer1 = New Observer1 (SubjectFor3D); Observer Observer2 = New Observer2 (SubjectFor3D); SubjectFor3D.Setmsg ("Le numéro 3D de 20140420 est: 127"); SubjectFor3D.Setmsg ("Le numéro 3D de 20140421 est: 333"); }}Résultat de sortie:
Observer1 obtient le numéro 3D -> Le numéro 3D de 20140420 est: 127, je veux l'écrire. Observer2 obtient le numéro 3D -> Le numéro 3D de 20140420 est: 127 Je veux dire à mes colocataires. Observer1 obtient le numéro 3D -> Le numéro 3D de 20140421 est: 333, je veux l'écrire. Observer2 obtient le numéro 3D -> Le numéro 3D de 20140421 est: 333 Je veux dire à mes colocataires.
Il existe de nombreux endroits dans JDK ou ANDORID qui implémentent le mode observateur, tels que xxxview.addxxxListEnti. Bien sûr, xxxview.setonxxxListener n'est pas nécessairement un mode observateur, car le mode observateur est une relation un-à-plusieurs. Pour SetXxxListener, il s'agit d'une relation 1 à 1, et elle doit être appelée un rappel.
Félicitations pour l'apprentissage du mode observateur. Le mode observateur ci-dessus nous permet de l'écrire à partir de zéro. Bien sûr, Java nous a aidés à mettre en œuvre le mode observateur, avec l'aide de java.util.observable et java.util.observer.
Ci-dessous, nous utilisons des classes intégrées Java pour implémenter le modèle d'observateur:
Tout d'abord, il y a un thème de numéro de service de loterie 3D:
package com.zhy.pattern.observer.java; import java.util.observable; La classe publique Subjectfor3d étend observable {private String msg; String public getmsg () {return msg; } / ** * Message de mise à jour de la rubrique * * @param msg * / public void setmsg (String msg) {this.msg = msg; setChanged (); notifyObservers (); }}Ce qui suit est le thème d'un numéro de service à double couleur:
package com.zhy.pattern.observer.java; import java.util.observable; La classe publique SubjectForSSQ étend observable {private String msg; String public getmsg () {return msg; } / ** * Message de mise à jour de la rubrique * * @param msg * / public void setmsg (String msg) {this.msg = msg; setChanged (); notifyObservers (); }}Enfin, nos utilisateurs:
package com.zhy.pattern.observer.java; import java.util.observable; import java.util.observer; classe publique Observer1 implémente l'observateur {public void registresbject (observable observable) {observable.addobserver (this); } @Override public void Update (observable o, objet arg) {if (o instanceof sumesfor3d) {sumesfor3d sujectfor3d = (subderfor3d) o; System.out.println ("MSG de SubjectFor3D ->" + SubjectFor3D.getMsg ()); } if (o instanceof sumesforssSQ) {sujectForsSq sujectFORSSQ = (sujectFORSSSQ) o; System.out.println ("MSG de SubjectForsSQ ->" + SubterForsSq.getMsg ()); }}}Regardez un code de test:
package com.zhy.pattern.observer.java; Public Class Test {public static void main (String [] args) {sujectFor3d Subterfor3d = new SubterFor3d (); SujectFORSSQ sujectFORSSQ = new SubterForsSSQ (); Observer1 Observer1 = New Observer1 (); Observer1.RegistersUbject (SubterFor3d); Observer1.RegistersUbject (SubsersSSQ); SubjectFor3D.Setmsg ("Hello 3D'nums: 110"); SubseauxforsSq.Setmsg ("SSQ'NUMS: 12,13,31,5,4,3 15"); }}Résultats des tests:
MSG de SubjectFor3d -> Bonjour 3D'nums: 110 MSG SUBJECTFORSSQ -> SSQ'NUMS: 12,13,31,5,4,3 15
On peut voir que l'utilisation de classes intégrées Java pour implémenter le modèle d'observateur, le code est très concis. Soit dit en passant, AddoBserver, SuppearObserver, NotifyObservers a été implémenté pour nous. Tout ce que nous pouvons voir qui observable est une classe, pas une interface. Fondamentalement, le livre a une attitude négative envers la conception de Java. Il estime que le modèle d'observateur intégré de Java viole le principe de la programmation orientée vers l'interface. Cependant, si vous y pensez, vous écrivez en effet le modèle d'observateur ici (notre propre implémentation). L'idée d'interface est très bonne, mais si vous continuez à ajouter de nombreux sujets maintenant, le DDOBServer, SupprimeObserver, NotifyObservers pour chaque sujet est essentiellement le même. Les interfaces ne peuvent pas implémenter la réutilisation du code, et il n'y a aucun moyen d'utiliser le mode combiné pour réaliser la réutilisation de ces trois méthodes, donc je pense qu'il est raisonnable d'implémenter ces trois méthodes dans la classe ici.