栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【韩老师设计模式10】观察者 消除if逻辑,Observable,中介者

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【韩老师设计模式10】观察者 消除if逻辑,Observable,中介者

观察者

天气预报项目需求
天气预报项目需求,具体要求如下:

  1. 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如
    发布到自己的网站或第三方)。

  2. 需要设计开放型API,便于其他第三方也能接入气象站获取数据。

  3. 提供温度、气压和湿度的接口

  4. 测量数据更新时,要能实时的通知给第三方

  5. 通过getXxx方法,可以让第三方接入,并得到相关信息.

  6. 当数据有更新时,气象站通过调用dataChange() 去更新数据,当第三方再次获
    取时,就能得到最新数据,当然也可以推送。

WeatherData维护:新浪,自己的公告板对象。

  • 然后去调用这些对象的dataChange(),即:推送
非模式 自己的网站
public class CurrentConditions {
	// 温度,气压,湿度
	private float temperature;
	private float pressure;
	private float humidity;

	//更新 天气情况,是由 WeatherData 来调用,我使用推送模式
	public void update(float temperature, float pressure, float humidity) {
		this.temperature = temperature;

        //别人调用update,就会调用展示的方法
		display();
	}

	//显示
	public void display() {
		System.out.println("***Today mTemperature: " + temperature + "***");
	}
}
核心天气类
  • 推送逻辑
public class WeatherData {
    
	private float temperatrue;

    //加入第三方
	private CurrentConditions currentConditions;

	public WeatherData(CurrentConditions currentConditions) {
		this.currentConditions = currentConditions;
	}

	//当数据有更新时,就调用 setData
	public void setData(float temperature, float pressure, float humidity) {
		this.temperatrue = temperature;

		//将最新的信息 推送给 接入方 currentConditions
		//调用 接入方的 update
		currentConditions.update(getTemperature(), getPressure(), getHumidity());
	}
    
}
		//创建接入方 currentConditions
		CurrentConditions c = new CurrentConditions();
		//创建 WeatherData 并将 接入方 currentConditions 传递到 WeatherData中
		WeatherData w = new WeatherData(c);
		
		//更新天气情况
		w.setData(30, 150, 40);
		
		//天气情况变化
		System.out.println("============天气情况变化=============");
		w.setData(40, 160, 20);
问题分析
  1. 其他第三方接入气象站获取数据的问题
  2. 无法在运行时动态的添加第三方 (新浪网站)
  3. 违反ocp原则=>观察者模式
    //在WeatherData中, 当增加一个第三方,都需要创建一个对应的第三方的公告板
    对象,并加入到dataChange, 不利于维护,也不是动态加入
public void dataChange() {
	currentConditions.update(getTemperature(), getPressure(), getHumidity());
}  
Observer 角色说明

观察者模式类似订牛奶业务

  1. 奶站/气象局: Subject
  2. 用户/第三方网站: Observer
主题接口 和 观察者介绍

 Subject:登记注册、移除和通知

  1. registerObserver 注册
  2. removeObserver 移除
  3. notifyObservers() 通知所有的注册的用户,
  • 根据不同需求,可以是更新数据,让用户来取,

  • 也可能是实施推送,看具体需求定

Observer:接收输入

  • 观察者模式:对象之间多对一依赖的一种设计方案,
    • 被依赖的对象为Subject,依赖的对象为Observer,
  • Subject通知Observer变化,
    • 比如这里的奶站是Subject,是1的一方。
    • 用户时Observer,是多的一方。
本次案例

Subject

  • registerObserver
  • remove
  • notifyObservers

子类:

  • WeatherData 有ArrayList 里面存 Observer

Observer

  • update

子类:

  • CurrentCondition 自己的天气公告
  • Baidu

Client 依赖:Subject 和 Observer

主题接口
//接口, 让WeatherData 来实现 
public interface Subject {
	
	public void registerObserver(Observer o);
	public void removeObserver(Observer o);
	public void notifyObservers();
}
主题的实现
public class WeatherData implements Subject {
	private float temperatrue;

	//观察者集合
	private ArrayList observers;
	
	//加入新的第三方
	public WeatherData() {
		observers = new ArrayList();
	}

	//当数据有更新时,就调用 setData
	public void setData(float temperature, float pressure, float humidity) {
		this.temperatrue = temperature;

		//将最新的信息 推送给 接入方 currentConditions
		notifyObservers();
	}
    
    	//遍历所有的观察者,并通知
	@Override
	public void notifyObservers() {

		for(int i = 0; i < observers.size(); i++) {
			observers.get(i).update(this.temperatrue, this.pressure, this.humidity);
		}
	}
    

	//注册一个观察者
	@Override
	public void registerObserver(Observer o) {
		observers.add(o);
	}

	//移除一个观察者
	@Override
	public void removeObserver(Observer o) {

		if(observers.contains(o)) {
			observers.remove(o);
		}
	}
}
观察者接口
//观察者接口,有观察者来实现
public interface Observer {

	public void update(float temperature, float pressure, float humidity);
}
观察者实现
  • 现状类,就是 自己的项目
public class CurrentConditions implements Observer {

	// 温度,气压,湿度
	private float temperature;

	// 更新 天气情况,是由 WeatherData 来调用,我使用推送模式
	public void update(float temperature, float pressure, float humidity) {
		this.temperature = temperature;

		display();
	}

	// 显示
	public void display() {
		System.out.println("***Today mTemperature: " + temperature + "***");
	}
}
Conditions
n.
条件,环境;疾病;条款(condition 的复数)
v.
训练,使习惯于;控制,制约;护理,保养;影响;加条件于(condition 的第三人称单数)

temperature
英
/ˈtemprətʃə(r)/
美
/ˈtemprətʃər; ˈtemprətʃʊr/
n.
温度,气温;体温;发烧;热烈程度,情绪激烈程度

pressure
英
/ˈpreʃə(r)/
美
/ˈpreʃər/
n.
压力,挤压;(气体或液体形成的)压力,压强;心理压力,紧张;催促,要求;气压
v.
对……施加压力,强迫;使……增压

humidity
英
/hjuːˈmɪdəti/
美
/hjuːˈmɪdəti/
n.
潮湿,湿气;湿度
测试
		//创建一个 天气局
		WeatherData w = new WeatherData();
		
		//创建具体观察者,公告板 和 百度
		CurrentConditions c = new CurrentConditions();
		BaiduSite b = new BaiduSite();
		
		//注册到 气象局
		w.registerObserver(c);
		w.registerObserver(b);
		
		//测试
		System.out.println("通知各个注册的观察者, 看看信息");
		w.setData(10f, 100f, 30.3f);
		
		//移除 公告板
		w.removeObserver(c);

		//测试
		System.out.println("通知各个注册的观察者, 看看信息");
		w.setData(10f, 100f, 30.3f);
通知各个注册的观察者, 看看信息
***Today mTemperature: 10.0***
***Today mPressure: 100.0***
***Today mHumidity: 30.3***
===百度网站====
***百度网站 气温 : 10.0***
***百度网站 气压: 100.0***
***百度网站 湿度: 30.3***

通知各个注册的观察者, 看看信息
===百度网站====
***百度网站 气温 : 10.0***
***百度网站 气压: 100.0***
***百度网站 湿度: 30.3***
模式好处

观察者模式的好处

  1. 观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除
    和通知。
  2. 这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核
    心类WeatherData不会修改代码, 遵守了ocp原则。
Observable
  • jdk的

  • 没有继承接口,类和接口 放在一起了。

public class Observable {
    private boolean changed = false;
    private Vector obs;

    public Observable() {
        obs = new Vector<>();
    }

    public synchronized void addObserver(Observer o) {
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }
    
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }
    
    public void notifyObservers() {
        notifyObservers(null);
    }
    
    public void notifyObservers(Object arg) {}
    
}
public interface Observer {

    void update(Observable o, Object arg);
}

观察者模式在Jdk应用的源码分析
3) 模式角色分析
- Observable 的作用和地位等价于 我们前面讲过Subject
- Observable 是类,不是接口,类中已经实现了核心的方法 ,即管理Observer
的方法 add… delete … notify…
- Observer 的作用和地位等价于我们前面讲过的 Observer, 有update
- Observable 和 Observer 的使用方法和前面讲过的一样,只是Observable 是
类,通过继承来实现观察者模式

使用 主题 实现类
public class Weather extends Observable {

    public Weather() {
        // changed = true; 说明已经改变,为了 源码过校验,执行方法
        setChanged();
    }
}
具体观察者
public class BaiduSite implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println(arg.toString());
        System.out.println(o.toString());
    }
}
       	//创建 气象局
       	Weather o=new Weather();

		//观察者
        BaiduSite b =new BaiduSite();

		//添加
        o.addObserver(b);
		//通知 观察者
        o.notifyObservers("张三");
中介者

智能家庭项目:

  1. 智能家庭包括各种设备,闹钟、咖啡机、电视机、窗帘 等
  2. 主人要看电视时,各个设备可以协同工作,自动完成看电视的准备工作,比如流
    程为: 闹铃响起->咖啡机开始做咖啡->窗帘自动落下->电视机开始播放

客户联系中介

  • 中介给 房主 和 房主的妻子,房主的父亲 联系。
  • 房主 和 房主的妻子,代码里 不让其联系 (否则会 很复杂)
传统的问题
  1. 当各电器对象有多种状态改变时,相互之间的调用关系会比较复杂
  2. 各个电器对象彼此联系, 你中有我,我中有你,不利于松耦合.
  3. 各个电器对象之间所传递的消息(参数),容易混乱
  4. 当系统增加一个新的电器对象时,或者执行流程改变时,代码的可维护性、扩展性
    都不理想  考虑中介者模式
基本介绍
  1. 中介者模式(Mediator Pattern) , 用一个中介对象来封装一系列的对象交互。
    中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立
    地改变它们之间的交互
  2. 中介者模式属于行为型模式, 使代码易于维护
  3. 比如MVC模式, C(Controller控制器)是M(Model模型)和V(View视图)的中
    介者,在前后端交互时起到了中间人的作用

Service 也是中介者,注入各种mapper,mapper之间是 不交互的。

colleague
英
/ˈkɒliːɡ/
美
/ˈkɑːliːɡ/
全球发音
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n.
同事,同僚

高中 | CET4 | CET6 | 考研 | IELTS | TOEFL | SAT
复数 colleagues
角色组成
  • Mediator

  • Concreate Mediator

    • 有HashMap,聚合 Colleague,管理所有的同事类
    • 完成 响应的操作 和 任务
  • Colleague

    • Concreate Colleague 构造自己的时候,拿到 Mediator,调用相关的方法
      • 都依赖中介者对象。他们之间没关系。
    • Concreate Colleague2 本案例为 :TM CoffeMachine
      • 有方法:send Message():
      • 和 getMediator 返回:Mediator
  • Client 依赖,Mediator 和 Colleague

alarm
英
/əˈlɑːm/
美
/əˈlɑːrm/
全球发音
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n.
警报;警报器;闹钟;惊恐,担忧
v.
使不安,使恐慌;给(门等)安装警报器

curtains
英
/ˈkɜːtənz/
美
/'kɜːtənz/
全球发音
简明 柯林斯 例句 百科
窗帘(curtain的复数)
be curtains for sb,对某人而言是灾难
设计模式 同事中介类
//同事抽象类
public abstract class Colleague {
	private Mediator mediator;
	public String name;

	public Colleague(Mediator mediator, String name) {
		this.mediator = mediator;
		this.name = name;
	}

	public Mediator GetMediator() {
		return this.mediator;
	}
	
	public abstract void SendMessage(int stateChange);
}
闹钟 和 TV类
//具体的同事类
public class Alarm extends Colleague {

	//构造器
	public Alarm(Mediator mediator, String name) {
		super(mediator, name);
        
		//在创建Alarm 同事对象时,将自己放入到ConcreteMediator 对象中[集合]
		mediator.Register(name, this);
	}

	public void SendAlarm(int stateChange) {
		SendMessage(stateChange);
	}

	@Override
	public void SendMessage(int stateChange) {
		//调用的中介者对象的getMessage
		this.GetMediator().GetMessage(stateChange, this.name);
	}

}
public class TV extends Colleague {

	public void StartTv() {
		System.out.println("It's time to StartTv!");
	}

	public void StopTv() {
		System.out.println("StopTv!");
	}
}
咖啡机
public class CoffeeMachine extends Colleague {

	public void StartCoffee() {
		System.out.println("It's time to startcoffee!");
	}

	public void FinishCoffee() {

		System.out.println("After 5 minutes!");
		System.out.println("Coffee is ok!");
		SendMessage(0);
	}
}
中介者类
public abstract class Mediator {
	//将给中介者对象,加入到集合中
	public abstract void Register(String colleagueName, Colleague colleague);

	//接收消息, 具体的同事对象发出
	public abstract void GetMessage(int stateChange, String colleagueName);

	public abstract void SendMessage();
}
具体中介者
//具体的中介者类
public class ConcreteMediator extends Mediator {
	//集合,放入所有的同事对象
	private HashMap colleagueMap;
	private HashMap interMap;

	public ConcreteMediator() {
		colleagueMap = new HashMap();
		interMap = new HashMap();
	}

	@Override
	public void Register(String colleagueName, Colleague colleague) {

		colleagueMap.put(colleagueName, colleague);

		if (colleague instanceof Alarm) {
			interMap.put("Alarm", colleagueName);
		} else if (colleague instanceof CoffeeMachine) {
			interMap.put("CoffeeMachine", colleagueName);
		} else if (colleague instanceof TV) {
			interMap.put("TV", colleagueName);
		} else if (colleague instanceof Curtains) {
			interMap.put("Curtains", colleagueName);
		}

	}

	//具体中介者的核心方法
	//1. 根据得到消息,完成对应任务
	//2. 中介者在这个方法,协调各个具体的同事对象,完成任务
	@Override
	public void GetMessage(int stateChange, String colleagueName) {

		//处理闹钟发出的消息
		if (colleagueMap.get(colleagueName) instanceof Alarm) {
			if (stateChange == 0) {
				((CoffeeMachine) (colleagueMap.get(interMap
						.get("CoffeeMachine")))).StartCoffee();
				((TV) (colleagueMap.get(interMap.get("TV")))).StartTv();
			} else if (stateChange == 1) {
				((TV) (colleagueMap.get(interMap.get("TV")))).StopTv();
			}

		} else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {
			((Curtains) (colleagueMap.get(interMap.get("Curtains"))))
					.UpCurtains();

		} else if (colleagueMap.get(colleagueName) instanceof TV) {
            //如果TV发现消息
		} else if (colleagueMap.get(colleagueName) instanceof Curtains) {
			//如果是以窗帘发出的消息,这里处理...
		}
	}

	@Override
	public void SendMessage() {
	}

}

使用
		//创建一个中介者对象
		Mediator mediator = new ConcreteMediator();
		
		//创建Alarm 并且加入到  ConcreteMediator 对象的HashMap
		Alarm alarm = new Alarm(mediator, "alarm");
		
		//创建了CoffeeMachine 对象,并  且加入到  ConcreteMediator 对象的HashMap
		CoffeeMachine coffeeMachine = new CoffeeMachine(mediator,
				"coffeeMachine");
		
		//创建 Curtains , 并  且加入到  ConcreteMediator 对象的HashMap
		Curtains curtains = new Curtains(mediator, "curtains");
		TV tV = new TV(mediator, "TV");
		
		//让闹钟发出消息
		alarm.SendAlarm(0);
		System.out.println("==========================");
		coffeeMachine.FinishCoffee();
		System.out.println("==========================");
		alarm.SendAlarm(1);
It's time to startcoffee!
It's time to StartTv!
==========================
After 5 minutes!
Coffee is ok!
I am holding Up Curtains!
==========================
StopTv!
注意细节

中介者模式的注意事项和细节

  1. 多个类相互耦合,会形成网状结构, 使用中介者模式将网状结构分离为星型结构,
    进行解耦
  2. 减少类间依赖,降低了耦合, 符合迪米特原则
  3. 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
  4. 如果设计不当,中介者对象本身变得过于复杂, 这点在实际使用时,要特别注意
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1014157.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号