设计模式之观察者模式(上)

观察者模式
1)概述
1.定义

定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

2.作用

建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。

在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

3.结构图
4.角色

Subject(目标):目标又称为主题,指被观察的对象,在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify(),目标类可以是接口,也可以是抽象类或具体类。

ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法,如果无须扩展目标类,则具体目标类可以省略。

Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。

ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法,通常在实现时,可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。

5.代码实现

观察者模式描述了如何建立对象与对象之间的依赖关系,以及如何构造满足这种需求的系统。

抽象目标类Subject

import java.util.*;

abstract class Subject {
  //定义一个观察者集合用于存储所有观察者对象
  protected ArrayList observers<Observer> = new ArrayList();
 
  //注册方法,用于向观察者集合中增加一个观察者
	public void attach(Observer observer) {
    observers.add(observer);
  }
 
  //注销方法,用于在观察者集合中删除一个观察者
	public void detach(Observer observer) {
    observers.remove(observer);
  }
 
  //声明抽象通知方法
	public abstract void notify();
}

具体目标类ConcreteSubject

public class ConcreteSubject extends Subject {
  //实现通知方法
	public void notify() {
    //遍历观察者集合,调用每一个观察者的响应方法
		for(Object obs:observers) {
			((Observer)obs).update();
		}
	}	
}

抽象观察者Observer

interface Observer {
  //声明响应方法
	public void update();
}

具体观察者ConcreteObserver

public class ConcreteObserver implements Observer {
  //实现响应方法
	public void update() {
		 //具体响应代码
	}
}
6.注意

在复杂的情况下,具体观察者类ConcreteObserver的update()方法在执行时需要使用到具体目标类ConcreteSubject中的状态(属性),因此在ConcreteObserver与ConcreteSubject之间有时候还存在关联或依赖关系,在ConcreteObserver中定义一个ConcreteSubject实例,通过该实例获取存储在ConcreteSubject中的状态。

2)完整解决方案
1.结构图

AllyControlCenter充当抽象目标类,ConcreteAllyControlCenter充当具体目标类,Observer充当抽象观察者,Player充当具体观察者。

2.代码实现
import java.util.*;
 
//抽象观察类
interface Observer {
	public String getName();
	public void setName(String name);
	public void help(); //声明支援盟友方法
	public void beAttacked(AllyControlCenter acc); //声明遭受攻击方法
}
 
//战队成员类:具体观察者类
class Player implements Observer {
	private String name;
 
	public Player(String name) {
		this.name = name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return this.name;
	}
	
  //支援盟友方法的实现
	public void help() {
		System.out.println("坚持住," + this.name + "来救你!");
	}
	
  //遭受攻击方法的实现,当遭受攻击时将调用战队控制中心类的通知方法notifyObserver()来通知盟友
	public void beAttacked(AllyControlCenter acc) {
        System.out.println(this.name + "被攻击!");
        acc.notifyObserver(name);		
	}
}
 
//战队控制中心类:目标类
abstract class AllyControlCenter {
	protected String allyName; //战队名称
	protected ArrayList<Observer> players = new ArrayList<Observer>(); //定义一个集合用于存储战队成员
	
	public void setAllyName(String allyName) {
		this.allyName = allyName;
	}
	
	public String getAllyName() {
		return this.allyName;
	}
	
  //注册方法
	public void join(Observer obs) {
		System.out.println(obs.getName() + "加入" + this.allyName + "战队!");
		players.add(obs);
	}
	
  //注销方法
	public void quit(Observer obs) {
		System.out.println(obs.getName() + "退出" + this.allyName + "战队!");
		players.remove(obs);
	}
	
  //声明抽象通知方法
	public abstract void notifyObserver(String name);
}
 
//具体战队控制中心类:具体目标类
class ConcreteAllyControlCenter extends AllyControlCenter {
	public ConcreteAllyControlCenter(String allyName) {
		System.out.println(allyName + "战队组建成功!");
		System.out.println("----------------------------");
		this.allyName = allyName;
	}
	
  //实现通知方法
	public void notifyObserver(String name) {
		System.out.println(this.allyName + "战队紧急通知,盟友" + name + "遭受敌人攻击!");
    //遍历观察者集合,调用每一个盟友(自己除外)的支援方法
    for(Object obs : players) {
      if (!((Observer)obs).getName().equalsIgnoreCase(name)) {
         ((Observer)obs).help();
      }
    }		
	}
}

客户端类

class Client {
	public static void main(String[] args) {
		//定义观察目标对象
    AllyControlCenter acc;
		acc = new ConcreteAllyControlCenter("金庸群侠");
		
    //定义四个观察者对象
		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);
	}
}
相关推荐
大圣数据星球2 小时前
Fluss 写入数据湖实战
大数据·设计模式·flink
suweijie7682 小时前
SpringCloudAlibaba | Sentinel从基础到进阶
java·大数据·sentinel
公贵买其鹿3 小时前
List深拷贝后,数据还是被串改
java
思忖小下3 小时前
梳理你的思路(从OOP到架构设计)_设计模式Template Method模式
设计模式·模板方法模式·eit
xlsw_6 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹7 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭8 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫8 小时前
泛型(2)
java
超爱吃士力架8 小时前
邀请逻辑
java·linux·后端
南宫生8 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论