资讯详情

【韩老师设计模式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   "***");  } } 

核心天气类

  • 推送逻辑
/** * 类是核心 * 1. 包括最新的天气信息 * 2. 含有 CurrentConditions 对象 * 3. 当数据更新时,主动调用 CurrentConditions对象update方法(含 display), * 这样,他们(访问者)就可以看到最新的信息 * */ 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();
}

主题的实现

/** * 类是核心 * 1. 包含最新的天气情况信息 * 2. 含有 观察者集合,使用ArrayList管理 * 3. 当数据有更新时,就主动的调用 ArrayList, 通知所有的(接入方)就看到最新的信息 */
public class WeatherData implements Subject { 
        
	private float temperatrue;

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

	//当数据有更新时,就调用 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<Observer> 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<String, Colleague> colleagueMap;
	private HashMap<String, String> interMap;

	public ConcreteMediator() { 
        
		colleagueMap = new HashMap<String, Colleague>();
		interMap = new HashMap<String, String>();
	}

	@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 

标签: 压力变送器tm21

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台