设计模式的艺术 行为型模式之观察者模式

前言

红灯停,绿灯行,在日常的交通中,每每遇到红灯,司机总是要在路口进行等待,等到绿灯才能通过,这个时候司机就扮演了一个观察者的角色,随着灯的颜色的变化,司机的行为也跟着变化,在软件系统中,有些对象之间也存在类似交通信号灯和汽车之间的关系,一个对象的的行为状态改变导致了其他对象的状态或行为也发生变化,他们之间将进行联动,正所谓"触一而牵百发",为了更好的描述对象之间存在着这种一对多的联动,观察者模式就应运而生了。它定义了对象之间一种一对多的依赖关系,让一个对象的改变能够影响其他对象

什么是观察者模式呢? Observer Pattern

定义对象之间的一种一对多的依赖关系,使得每当一个对象状态发生改变时,其相关的依赖对象皆得到通知并自动更新,观察者模式的别名包括发布-订阅(Publish/Subscribe)模式,模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或者从属者(Dependents)模式。观察者模式是一种对象行为型模式

观察者模式的优点

(1)、观察者模式可以实现表示层和数据逻辑层分离,定义了稳定的消息更新传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色

(2)、观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察目标只需要维持一个抽象观察者的集合,无须了解其具体观察者。由于观察目标和观察者没有紧密的耦合在一起,因此他们可以属于不同的抽象化层次

(3)、观察者模式支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度

(4)、观察者模式满足开闭原则的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便

观察者模式的缺点

(1)、如果一个观察对象目标有很多直接和简介观察者,将所有的观察者都通知到会花费很多时间。

(2)、如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃

(3)、观察者模式没有相应的机制让观察者知道所观察的目标是怎么变化的,而仅仅只是知道观察目标发生了变化

观察者模式的适用场景

(1)、一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用

(2)、一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将发生改变,也不知道这些对象是谁

(3)、需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象。。。。,可以使用观察者模式创建一种链式触发机制。

观察者模式的具体实现

目录结构

抽象观察者

package com.company;

//抽象观察者
public interface Observer {
    String getName();

    void setName(String name);

    void help();  //声明支援盟友方法

    void beAttacked(AllyControllCenter aco);   //声明遭受攻击的方法
}

具体观察者

package com.company;

//战队成员类:具体观察者
public class Player implements Observer {
    private String name;

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


    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name=name;
    }

    @Override
    //支援盟友的方法
    public void help() {
        System.out.println("坚持住,"+this.name+"来救你");
    }

    @Override
    //遭受攻击方法的实现,当遭受攻击时将调用战队控制中心类的通知方法notifyObserver()
    //通知盟友
    public void beAttacked(AllyControllCenter aco) {
            System.out.println(this.name+"被攻击!");
            aco.notifyObserver(name);
    }
}

控制类

package com.company;

import java.util.ArrayList;

//战队控制中心类:目标类
public abstract class AllyControllCenter {
    protected String allyName;   //战队名称
    protected ArrayList<Observer> players=new ArrayList<Observer>();  //定义一个集合存储战队成员
    //注册方法
    public void join(Observer abs){
        players.add(abs);
        System.out.println(abs.getName()+"加入"+this.allyName+"战队!");

    }
    //声明抽象通知方法
    public abstract void notifyObserver(String name);

    //注销方法
    public void quit(Observer abs){
        System.out.println(abs.getName()+"退出"+this.allyName+"战队!");
        players.remove(abs);
    }



    public String getAllyName() {
        return allyName;
    }

    public void setAllyName(String allyName) {
        this.allyName = allyName;
    }

    public ArrayList<Observer> getPlayers() {
        return players;
    }

    public void setPlayers(ArrayList<Observer> players) {
        this.players = players;
    }
}

具体目标类

package com.company;

//具体战队控制中心类:具体目标类
public class ConcreteAllyControllCenter extends  AllyControllCenter{
    public ConcreteAllyControllCenter(String allyName){
        System.out.println(allyName+"战队组建成功!");
        System.out.println("--------------");
        this.allyName=allyName;
    }

    @Override
    //实现通知方法
    public void notifyObserver(String name) {
        System.out.println(this.allyName+"战队紧急通知,盟友"+name+"遭受敌人攻击!");
        //遍历观察者集合,调用每一个盟友(自己除外)的支援方法
        for(Object abs:players){
            if(!((Observer)abs).getName().equalsIgnoreCase(name)){
                ((Observer) abs).help();
            }
        }
    }
}

测试类

package com.company;

public class Main {

    public static void main(String[] args) {
           //定义观察目标对象
        AllyControllCenter acc;
        acc=new ConcreteAllyControllCenter("金庸群侠");
        //定义四个观察者对象
        Observer player1,player2,player3,player4;
        player1=new Player("杨过");
        acc.join(player1);
        player2=new Player("令狐冲");
        acc.join(player2);
        player3=new Player("张无忌");
        acc.join(player3);
        player4=new Player("段誉");
        acc.join(player4);
        //某成员遭受攻击
        player1.beAttacked(acc);
    }
}

转载请注明出处,掌声送给社会

猜你喜欢

转载自blog.csdn.net/SCDN_CP/article/details/83306371