デザインモードのオブザーバーモードとビジターモードの詳しい説明と応用

目次


1.ビジターモードの詳細説明

1.1 訪問者パターンの定義

意味:

ビジターパターン[visitor Pattern]は、データ構造とデータ操作を分離した設計パターンです。を指す

データ構造の要素を操作する操作をカプセル化します。

特徴:

これらの要素に対する新しい操作は、データ構造を変更せずに定義できます。

行動モデルに属します。

説明します:

ビジター パターンは、最も複雑なデザイン パターンとして知られています。あまり使用されていません。

1.1.1 ビジターモードの日常生活への具現化

1. KPI評価の参加者

KPIの評価基準は一般的に固定されていますが、KPIの評価に参加する従業員は頻繁に変わります。

KPI評価を採点する人も頻繁に変わります。

2.レストランスタッフ

レストランで食事をする場合、レストランのメニューは基本的に安定しており、ダイナーは基本的に毎日変わります。ダイナーは訪問者です。

要約:

訪問者は変化する要素のようであり、不変の構造 [基準、規則] との構成関係がその役割を果たします。

1.1.2 訪問者モードの適用シナリオ

訪問者モードはめったに使用されず、一度使用する必要がある場合、関連するシステムはより複雑になることがよくあります。

1. データ構造が安定しており、データ構造の操作が頻繁に変更される。

2. データ構造とデータ操作の分離が必要なシナリオ。

3. 特定の種類のシナリオを判断するために分岐を使用せずに、さまざまなデータ型 (要素) を操作する必要があります。

1.2 訪問者パターンの一般的な実装

1.3 訪問者モードのユースケースの KPI 評価

1.3.1 クラス図の設計

画像

1.3.2 コードの実装

1. 要素のトップレベル インターフェイス定義

package com.oldlu.visitor.demo.kpi;

import java.util.Random;

/**
 * @ClassName Employee
 * @Description 员工,元素抽象
 * @Author oldlu
 * @Date 2020/6/24 10:38
 * @Version 1.0
 */
public abstract class Employee {
    
    
    private String name;
    private int kpi;

    public Employee(String name) {
    
    
        this.name = name;
        this.kpi = new Random().nextInt(10);
    }

    public abstract void accept(IVisitor visitor);

    public String getName() {
    
    
        return name;
    }

    public int getKpi() {
    
    
        return kpi;
    }
}

2. 要素固有の実現

package com.oldlu.visitor.demo.kpi;

import java.util.Random;

/**
 * @ClassName Engineer
 * @Description 普通开发人员
 * @Author oldlu
 * @Date 2020/6/24 10:43
 * @Version 1.0
 */
public class Engineer extends Employee{
    
    
    public Engineer(String name) {
    
    
        super(name);
    }

    @Override
    public void accept(IVisitor visitor) {
    
    
        visitor.visit(this);
    }
    //考核:代码量
    public int getCodingLine(){
    
    
        return new Random().nextInt(100000);
    }

}
package com.oldlu.visitor.demo.kpi;

import java.util.Random;

/**
 * @ClassName Manager
 * @Description 项目经理
 * @Author oldlu
 * @Date 2020/6/24 10:44
 * @Version 1.0
 */
public class Manager extends Employee {
    
    
    public Manager(String name) {
    
    
        super(name);
    }

    @Override
    public void accept(IVisitor visitor) {
    
    
        visitor.visit(this);
    }
    //考核:每年的新产品研发数量
    public int getProducts(){
    
    
        return new Random().nextInt(10);
    }
}

3. ビジターのトップレベル インターフェイスと実装

package com.oldlu.visitor.demo.kpi;

/**
 * @ClassName IVisitor
 * @Description 访问者接口
 * @Author oldlu
 * @Date 2020/6/24 10:41
 * @Version 1.0
 */
public interface IVisitor {
    
    
    //传参具体的元素
    void visit(Engineer engineer);

    void visit(Manager manager);
}
package com.oldlu.visitor.demo.kpi;

/**
 * @ClassName CTOVisitor
 * @Description ceo考核者,只有看kpi打分就行
 * @Author oldlu
 * @Date 2020/6/24 10:49
 * @Version 1.0
 */
public class CEOVisitor implements IVisitor{
    
    

    @Override
    public void visit(Engineer engineer) {
    
    
        System.out.println("工程师:"+engineer.getName()+" ,KPI:"+engineer.getKpi());
    }

    @Override
    public void visit(Manager manager) {
    
    
        System.out.println("项目经理:"+manager.getName()+" ,KPI:"+manager.getKpi());
    }
}
package com.oldlu.visitor.demo.kpi;

/**
 * @ClassName CTOVisitor
 * @Description cto考核者
 * @Author oldlu
 * @Date 2020/6/24 10:49
 * @Version 1.0
 */
public class CTOVisitor implements IVisitor{
    
    

    @Override
    public void visit(Engineer engineer) {
    
    
        System.out.println("工程师:"+engineer.getName()+" ,编写代码行数:"+engineer.getCodingLine());
    }

    @Override
    public void visit(Manager manager) {
    
    
        System.out.println("项目经理:"+manager.getName()+" ,产品数量:"+manager.getProducts());
    }
}

4. データ構造定義

package com.oldlu.visitor.demo.kpi;

import java.util.LinkedList;
import java.util.List;

/**
 * @ClassName BusinessReport
 * @Description 业务报表,数据结构
 * @Author oldlu
 * @Date 2020/6/24 10:55
 * @Version 1.0
 */
public class BusinessReport {
    
    
    private List<Employee> employeeList = new LinkedList<>();

    public BusinessReport() {
    
    
        employeeList.add(new Manager("项目经理A"));
        employeeList.add(new Manager("项目经理B"));
        employeeList.add(new Engineer("程序员A"));
        employeeList.add(new Engineer("程序员B"));
        employeeList.add(new Engineer("程序员C"));
    }

    public void showReport(IVisitor visitor){
    
    
        for (Employee employee : employeeList) {
    
    
            employee.accept(visitor);
        }
    }
}

5. テストコード

package com.oldlu.visitor.demo.kpi;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author oldlu
 * @Date 2020/6/24 10:54
 * @Version 1.0
 */
public class Test {
    
    
    public static void main(String[] args) {
    
    
        BusinessReport report = new BusinessReport();
        System.out.println("===========CEO看报表===============");
        report.showReport(new CEOVisitor());
        System.out.println("===========CTO看报表===============");
        report.showReport(new CTOVisitor());
    }
}

試験結果:

画像

説明します:

ビジターのトップレベル インターフェイスが定義されると、visit オーバーロード メソッドが内部で定義され、サブクラスがさまざまな visit 要素の実装に対してオーバーロードされます。

メソッドとしてデザインしてみませんか?

ここには特定の要素を関連付ける方法があるからです。

システムが要素実装サブクラスを追加する必要がある場合、実装サブクラスを 1 つだけ追加する必要があり、オーバーロードされたメソッドがインターフェイスに追加されます。

システムの拡張が容易です。

1.4 訪問者パターンの拡張 - ディスパッチ

Javaでの静的ディスパッチと動的ディスパッチ。二重発送もあります。

Java でのディスパッチは、メソッドのオーバーロードの特殊な形式です。つまり、オーバーロードされたメソッドには、同じメソッド名、同じ数のパラメーター、および異なるタイプのフォームがあります。

1.4.1 Java での静的ディスパッチのサンプル コード

package com.oldlu.visitor.dispatch;

/**
 * @ClassName Main
 * @Description 测试静态分派
 * @Author oldlu
 * @Date 2020/6/24 11:20
 * @Version 1.0
 */
public class Main {
    
    
    public static void main(String[] args) {
    
    
        String str = "1";
        Integer integer = 1;
        Main main = new Main();
        main.test(integer);
        main.test(str);
    }
    public void test(String str){
    
    
        System.out.println("String "+str);
    }
    public void test(Integer integer){
    
    
        System.out.println("Integer "+integer);
    }
}

説明します:

上記のテスト コードでは、テスト メソッドに 2 つのオーバーロードされたメソッドがあり、パラメーターの数は同じで型が異なります。

コンパイル段階では、パラメーターの型を明確に知ることができます。これは静的代入と呼ばれます。

同じメソッド名、異なるタイプの異なるメソッド、この形式は複数のディスパッチとも呼ばれます。

1.4.2 Java での動的ディスパッチ

プログラムのコンパイル段階では、それがどのタイプであるかは明確ではありません。実行時にのみ、それがどのタイプであるかを知ることができます。

動的ディスパッチと呼ばれます。

1. インターフェースと実装を定義する

package com.oldlu.visitor.dispatch.dynamic;

/**
 * @ClassName Person
 * @Description 接口定义
 * @Author oldlu
 * @Date 2020/6/24 11:33
 * @Version 1.0
 */
public interface Person {
    
    
    void test();
}
package com.oldlu.visitor.dispatch.dynamic;

/**
 * @ClassName Women
 * @Description 女人
 * @Author oldlu
 * @Date 2020/6/24 11:35
 * @Version 1.0
 */
public class Women implements Person{
    
    
    @Override
    public void test() {
    
    
        System.out.println("女人");
    }
}
package com.oldlu.visitor.dispatch.dynamic;

/**
 * @ClassName Man
 * @Description 男人
 * @Author oldlu
 * @Date 2020/6/24 11:34
 * @Version 1.0
 */
public class Man implements Person {
    
    
    @Override
    public void test() {
    
    
        System.out.println("男人");
    }
}

2.テストクラス

package com.oldlu.visitor.dispatch.dynamic;

/**
 * @ClassName Main
 * @Description 测试类
 * @Author oldlu
 * @Date 2020/6/24 11:35
 * @Version 1.0
 */
public class Main {
    
    
    public static void main(String[] args) {
    
    
        Person man = new Man();
        Person women = new Women();
        man.test();
        women.test();
    }
}

説明します:

コンパイル時に、実行時にのみ、男性または女性が自分がどのタイプであるかがわからない場合、

特定のタイプは、インスタンスが new によって作成された場合にのみ認識されるため、動的割り当てです。

1.4.3 ビジターパターンにおける疑似動的二重ディスパッチ

データ構造では、コレクション要素は通常トラバースされます。次のように:

画像

これは動的割り当てであり、accept メソッドが呼び出されていることがわかりますが、特定の型は実行時まで決定できません。

また、Employee も抽象インタフェースであり、型を判別できません。

画像

Engineer などのサブクラスに入ると、accept メソッドは visit メソッドを呼び出し、パラメーター this を渡します。これも動的にディスパッチされます。する必要がある

タイプは実行時にのみ決定できます。[このインスタンスは実行時に作成する必要があるため]

画像

1.5 ソースコードにビジターモードを適用

1.5.1 jdk中FileVisitor

FileVisitResult visitFile(T file, BasicFileAttributes attrs)
    throws IOException;

visitFile メソッドは FileVisitor インターフェースで定義されています。パラメータを BasicFileAttributes に渡すこともインターフェイスです。

1.5.2 spring中BeanDefinitionVisitor

public void visitBeanDefinition(BeanDefinition beanDefinition) {
    
    
        visitParentName(beanDefinition);
        visitBeanClassName(beanDefinition);
        visitFactoryBeanName(beanDefinition);
        visitFactoryMethodName(beanDefinition);
        visitScope(beanDefinition);
        if (beanDefinition.hasPropertyValues()) {
    
    
            visitPropertyValues(beanDefinition.getPropertyValues());
        }
        if (beanDefinition.hasConstructorArgumentValues()) {
    
    
            ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
            visitIndexedArgumentValues(cas.getIndexedArgumentValues());
            visitGenericArgumentValues(cas.getGenericArgumentValues());
        }
    }

アクセスすると、その内容は変更されませんが、対応する結果が返されます。データ操作を構造から分離します。

1.6 訪問者モードの使用のまとめ

1.6.1 長所と短所のまとめ

アドバンテージ:

1. データ構造とデータ操作を分離し、操作セットを使用して独立して変更する

2. 優れたスケーラビリティ: 訪問者の役割を拡張することで、データセットに対するさまざまな操作を実現できます

3. 特定の種類の要素は単一ではなく、すべての訪問者が操作できます

4. 単一責任の原則に沿った、各役割の責任の分離。

欠点:

1. 要素タイプを追加できない: システム データ構造オブジェクトが変更しやすい場合、新しいデータ オブジェクトが頻繁に追加されます。

次に、訪問者クラスは、対応する要素の操作を増やす必要があります。これは、開閉の原則に違反しています。

2. 特定の要素を変更することは困難です。特定の要素に属性を追加したり、属性を削除したり、その他の操作を行うと、対応するビジター クラスが必要になります。

対応する変更、特に多数のビジター クラスがある場合、変更の範囲が大きすぎます。

3. 依存性逆転の原則の違反: 「差別的な扱い」を実現するために、訪問者は抽象化ではなく、特定の要素タイプに依存します。

2 オブザーバーモードの詳細説明

2.1 Observer パターンの定義

意味:

オブザーバー モード [オブザーバー パターン]、別名パブリッシュ-サブスクライブ [パブリッシュ/サブスクライブ] モード、モデル ビュー [モデル/ビュー] モード、

ソースリスナー [Source/Listener] モード、スレーブ [Dependents] モード。

1 対多の関係を定義します。サブジェクト オブジェクトは複数のオブザーバー オブジェクトによって同時に監視できます。これにより、サブジェクト オブジェクトの状態が変化するたびに、すべての

それに依存するオブジェクトは通知され、自動的に更新されます。

行動モデルに属します。

2.1.1 ライフシーンにおける観察者パターンの適用

1.アプリコーナーのお知らせ

2.目覚まし時計の設定

2.1.2 オブザーバーモードの適用シナリオ

1. 抽象モデルに 2 つの側面が含まれ、一方が他方に依存する場合。

2. 1 つまたは複数の他のオブジェクトの変更は、別のオブジェクトの変更に依存します。

3. ブロードキャスト メカニズムと同様の機能を実現します。特定のリスナーを知る必要はありません。ブロードキャストを配信するだけで、システムに関心があります。

オブジェクトはブロードキャストを自動的に受信します。

4. マルチレイヤー ネスティングを使用してチェーン トリガー メカニズムを形成します。これにより、ドメイン全体 (2 つのオブザーバー タイプ) でイベントを通知できます。

2.2 質疑応答プロンプト オブザーバー モード アプリケーション ケースのコーナー マーク

学習コミュニティでは、質問がある場合は、質問を投稿して助けを求めることができます。質問を投稿するときに、誰か [または教師] を招待することができます。

答え。

ただし、通常、教師は非常に忙しく、常にページを更新するとは限りません。そのため、通知機能が作られます。

質問があれば先生に出すと、通知アイコンの数字が1つ増えます。

先生がページにログインすると、通知コーナーをチェックするだけで、誰かが質問しているかどうかを知ることができ、回答に便利です。

2.2.1 クラス図の設計

画像

2.2.2 コードの実装

説明: これは、jdk に基づくパブリッシュ/サブスクライブ API の実装です。

1. 観測対象の定義

package com.oldlu.observer.demo.gper;

import java.util.Observable;

/**
 * @ClassName GPer
 * @Description 社区生态圈,被观察者
 * @Author oldlu
 * @Date 2020/6/24 17:31
 * @Version 1.0
 */
public class GPer extends Observable {
    
    
    private String name = "GPer 生态圈";

    public String getName() {
    
    
        return name;
    }

    private static final GPer gper = new GPer();

    private GPer() {
    
    
    }

    public static GPer getInstance(){
    
    
        return gper;
    }

    public void publishQuestion(Question question){
    
    
        System.out.println(question.getUserName()+" 在" +this.name +"提交了一个问题");
        //调用jdk api
        setChanged();
        notifyObservers(question);
    }
}

2. データ構造、問題クラス

package com.oldlu.observer.demo.gper;

/**
 * @ClassName Question
 * @Description 问题
 * @Author oldlu
 * @Date 2020/6/24 17:34
 * @Version 1.0
 */
public class Question {
    
    
    //问题发布者
    private String userName;
    //内容
    private String content;

    public void setUserName(String userName) {
    
    
        this.userName = userName;
    }

    public void setContent(String content) {
    
    
        this.content = content;
    }

    public String getUserName() {
    
    
        return userName;
    }

    public String getContent() {
    
    
        return content;
    }
}

3. オブザーバーの定義

package com.oldlu.observer.demo.gper;

import java.util.Observable;
import java.util.Observer;

/**
 * @ClassName Teacher
 * @Description 观察者
 * @Author oldlu
 * @Date 2020/6/24 17:38
 * @Version 1.0
 */
public class Teacher implements Observer {
    
    
    private String name;

    public Teacher(String name) {
    
    
        this.name = name;
    }

    @Override
    public void update(Observable ob, Object arg) {
    
    
        GPer gper = (GPer) ob;
        Question question = (Question) arg;
        System.out.println("===================");
        System.out.println(name+"老师,你好\n" +
                ",您收到一个来自"+gper.getName()+"的提问,希望你解答,问题内容如下:\n"+question.getContent()+
                "\n提问者:"+question.getUserName());
    }
}

4.テストクラス

package com.oldlu.observer.demo.gper;

import javax.management.Query;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author oldlu
 * @Date 2020/6/24 17:44
 * @Version 1.0
 */
public class Test {
    
    
    public static void main(String[] args) {
    
    
        GPer gper = GPer.getInstance();
        Teacher tom = new Teacher("tom");
        Teacher jerry = new Teacher("Jerry");

        gper.addObserver(tom);
        gper.addObserver(jerry);

        //用户行为
        Question question = new Question();
        question.setUserName("张三");
        question.setContent("观察者模式适用于哪些场景?");
        gper.publishQuestion(question);
    }
}

2.3 オブザーバー モードを実装する Google オープン ソース コンポーネント

依存パッケージ:

<dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>18.0</version>
    </dependency>

2.3.1 サンプルコード

1.オブザーバークラス

package com.oldlu.observer.guava;

import com.google.common.eventbus.Subscribe;

/**
 * @ClassName GuavaEvent
 * @Description 观察者
 * @Author oldlu
 * @Date 2020/6/24 18:07
 * @Version 1.0
 */
public class GuavaEvent {
    
    
    //表示观察者回调
    @Subscribe
    public void observer(String str){
    
    
        System.out.println("执行observer方法,传参为:"+str);
    }
}

2.テストクラス

package com.oldlu.observer.guava;

import com.google.common.eventbus.EventBus;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author oldlu
 * @Date 2020/6/24 18:09
 * @Version 1.0
 */
public class Test {
    
    
    public static void main(String[] args) {
    
    
        EventBus eventBus = new EventBus();
        GuavaEvent event = new GuavaEvent();
        eventBus.register(event);

        eventBus.post("tom");
    }
}

試験結果:画像

2.4 オブザーバー モードのアプリケーション ケースでのマウス イベントの相互作用

マウスがアクション [クリック、移動、スクロールなど] を開始したとき。. . ] 対応する応答を取得します。

アクションを発行するには、監視する必要があります [実際には、オペレーティング システムが監視します]。

マウス: オブザーバーとして実装されます。

イベント リスナー: アクションをリッスンする [イベントをトリガーする]

ビジネス クラス: イベント クラス [パラメーターを渡し、さまざまなイベントまたはアクションを区別する]

イベント コールバック: リッスン後、応答してコールバックを行う必要があります。オブザーバーとして行動します。

2.4.1 クラス図の設計

画像

2.4.2 コードの実装

1. イベントリスナー

package com.oldlu.observer.mouseclick.core;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName EventListener
 * @Description 事件监听器,被观察者的抽象
 * @Author oldlu
 * @Date 2020/6/24 18:21
 * @Version 1.0
 */
public class EventListener {
    
    
    protected Map<String, Event> events = new HashMap<String,Event>();

    public void addListener(String eventType, Object target, Method callback){
    
    
        events.put(eventType,new Event(target,callback));
    }
    public void addListener(String eventType, Object target){
    
    
        try{
    
    
            this.addListener(eventType,target,target.getClass().getMethod("on"+ toUpperFirstCase(eventType),Event.class));

        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }

    private String toUpperFirstCase(String eventType) {
    
    
        char [] chars = eventType.toCharArray();
        if(chars[0]> 'a' && chars[0] < 'z'){
    
    
            chars[0] -= 32;
        }
        return String.valueOf(chars);
    }

    private void trigger(Event event){
    
    
        event.setSource(this);
        event.setTime(System.currentTimeMillis());
        try{
    
    
            if(null != event.getCallback()){
    
    
                //反射调用 回调函数
                event.getCallback().invoke(event.getTarget(),event);
            }
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }

    protected void trigger(String trigger){
    
    
        if(!this.events.containsKey(trigger)){
    
    return;}
        //如果已进行注册,回调
        trigger(this.events.get(trigger).setTrigger(trigger));

    }
}

2. 監視対象、マウスクラス

package com.oldlu.observer.mouseclick.event;

import com.oldlu.observer.mouseclick.core.EventListener;

/**
 * @ClassName Mouse
 * @Description 具体的被观察者
 * @Author oldlu
 * @Date 2020/6/24 18:21
 * @Version 1.0
 */
public class Mouse extends EventListener {
    
    
    public void click() {
    
    
        System.out.println("调用单机方法");
        this.trigger(MouseEventType.ON_CLICK);
    }
}

3. イベント コールバック

package com.oldlu.observer.mouseclick.event;

import com.oldlu.observer.mouseclick.core.Event;

/**
 * @ClassName MouseCallback
 * @Description 事件响应,回调,观察者
 * @Author oldlu
 * @Date 2020/6/24 18:22
 * @Version 1.0
 */
public class MouseEventCallback {
    
    
    public void onClick(Event event){
    
    
        System.out.println("=============触发鼠标单击事件========\n"+event);
    }

    public void onMove(Event event){
    
    
        System.out.println("触发鼠标双击事件");
    }

}

4. パラメータ Bean、イベント クラスを渡す

package com.oldlu.observer.mouseclick.core;

import java.lang.reflect.Method;

/**
 * @ClassName Event
 * @Description 事件抽象,传参对象
 * @Author oldlu
 * @Date 2020/6/24 18:22
 * @Version 1.0
 */
public class Event {
    
    
    //事件源,如:鼠标,键盘
    private Object source;
    //事件触发,要通知谁(观察者)
    private Object target;

    private Method callback;
    //事件名称
    private String trigger;
    //事件触发时间
    private Long time;

    public Event(Object target, Method callback) {
    
    
        this.target = target;
        this.callback = callback;
    }

    public Object getSource() {
    
    
        return source;
    }

    public Event setSource(Object source) {
    
    
        this.source = source;
        return this;
    }

    public Object getTarget() {
    
    
        return target;
    }

    public Event setTarget(Object target) {
    
    
        this.target = target;
        return this;
    }

    public Method getCallback() {
    
    
        return callback;
    }

    public Event setCallback(Method callback) {
    
    
        this.callback = callback;
        return this;
    }

    public String getTrigger() {
    
    
        return trigger;
    }

    public Event setTrigger(String trigger) {
    
    
        this.trigger = trigger;
        return this;
    }

    public Long getTime() {
    
    
        return time;
    }

    public Event setTime(Long time) {
    
    
        this.time = time;
        return this;
    }


    @Override
    public String toString() {
    
    
        return "Event{" +
                "source=" + source +
                ", target=" + target +
                ", callback=" + callback +
                ", trigger='" + trigger + '\'' +
                ", time=" + time +
                '}';
    }
}

5. イベント型定数定義

package com.oldlu.observer.mouseclick.event;

/**
 * @ClassName MouseEventType
 * @Description 鼠标事件
 * @Author oldlu
 * @Date 2023/2/19 10:47
 * @Version 1.0
 */
public interface MouseEventType {
    
    
    String ON_CLICK = "click";
}

6.テストクラス

package com.oldlu.observer.mouseclick;

import com.oldlu.observer.mouseclick.event.Mouse;
import com.oldlu.observer.mouseclick.event.MouseEventCallback;
import com.oldlu.observer.mouseclick.event.MouseEventType;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author oldlu
 * @Date 2023/2/19 11:15
 * @Version 1.0
 */
public class Test {
    
    
    public static void main(String[] args) {
    
    
        MouseEventCallback callback = new MouseEventCallback();
        Mouse mouse = new Mouse();
        mouse.addListener(MouseEventType.ON_CLICK,callback);

        mouse.click();
    }
}

テスト結果は次のとおりです。

画像

2.5 ソース コードでのオブザーバー モードの適用

2.5.1 jdk中ServletContextListener

実際、オブザーバー モードの典型的なリマインダー *Listener [listener]

public interface ServletContextListener extends EventListener {
    
    

    public void contextInitialized ( ServletContextEvent sce );
    public void contextDestroyed ( ServletContextEvent sce );
}

2.5.2 spring中ContextLoaderListener

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    
    
    public ContextLoaderListener() {
    
    
    }

    public ContextLoaderListener(WebApplicationContext context) {
    
    
        super(context);
    }

    public void contextInitialized(ServletContextEvent event) {
    
    
        this.initWebApplicationContext(event.getServletContext());
    }

    public void contextDestroyed(ServletContextEvent event) {
    
    
        this.closeWebApplicationContext(event.getServletContext());
        ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }
}

2.6 オブザーバーの使用のまとめ

2.6.1 利点のまとめ

1. オブザーバーとオブザーバードは疎結合であり、依存性反転の原則に沿っています。

2. プレゼンテーション層(オブザーバー)とデータロジック層(オブザーブド)を分離し、データの変化を検知できるトリガー機構を確立する

複数のプレゼンテーション層への応答。

3. 1 対多の通信メカニズムを実現し、イベント登録メカニズムをサポートし、興味分配メカニズムをサポートし、オブザーバーがイベントをトリガーすると、興味がある場合のみ

のオブザーバーは通知を受け取ることができます。

2.6.2 短所のまとめ

1. オブザーバーが多すぎると、イベント通知に時間がかかります。

2. イベント通知には線形関係があり、オブザーバーの 1 つがイベントの処理でスタックすると、後続のオブザーバーがイベントを受信するのに影響します。

3. オブザーバーと被監視対象の間に循環依存関係がある場合、両者の間で循環呼び出しが発生し、システム クラッシュが発生する可能性があります。

おすすめ

転載: blog.csdn.net/ZGL_cyy/article/details/129109669