1.1定义

慨念:定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

即:主题和观察者定义了一对多的关系,观察者依赖于主题,只要主题发生变化,观察者就会被通知。

目的:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

1.2 底层机制

将一个状态会发生改变的对象定义成主题,所有的依赖对象定义为观察者。建立主题接口,对象使用该接口注册为观察者,或者把自己从观察者中删除。定义一个具体的主题类实现主题接口。建立观察者接口,声明更新状态的方法,具体的观察者都要实现此接口。当主题状态发生改变时,通过观察者接口将改变发送给具体的观察者。

1.3实现方式

1、观察者模式必须包含两个角色:主题和观察者。业务数据是主题,用户界面是观察者。当主题数据发生改变是会通知观察者,观察者做出的相应响应。

2、实现观察者模式的方法不止一种,最为直接的一种为:注册、通知、撤销。

1.4体现的设计原则

1、为了交互对象之间的松耦合设计而努力。

2、找出程序中会变化的方面,然后将其和固定不变的方面相分离。

3、针对接口编程,不针对实现编程。

4、多用组合,少用继承。

1.5优缺点

优点:

1、观察者模式提供了一种对象设计,让主题和观察者之间松耦合。

2、建立了一套触发机制。

缺点:

1、如果主题有很多的直接或间接的观察者,将改变通知到所有的观察者需要花费很长时间。

2、主题不知道观察者得细节,只知道观察者实现了主题的接口。

3、如果主题和观察之间存在循环依赖,可会导致系统崩溃。

1.6 类图

1.7 案例:气象观测站

简介:建立一个应用,利用WeatherData对象取得数据,并且更新三个布告板:目前状况,气象统计和天气预报。

1.7.1 类图

1.7.2代码逻辑

1、首先我们从接口开始建立,建立主题接口和观察者接口,以及界面显示接口。

2、在weatherData中实现主题接口。

3、建立布告板。

4、编写测试程序。

1.7.3代码实现

1、实现主题接口()

public interface Subject {

public void registerObserver(Observer o);//注册

public void removeObserver(Observer o);//删除

public void notifyObservers();//通知

}

2、实现观察者接口

public interface Observer {

public void update(float temp,float humidity,float pressure);//数据更新

}

3、实现布告板接口

public interface DisplayElement {

public void display();//显示界面

}

4、完成WeatherData类实现主题接口

public class WeatherDate implements Subject {

private ArrayList observers;//记录观察者,ArrayList是在构造器中建立的。

private float temperature;

private float humidity;

private float pressure;

public WeatherDate() {

observers = new ArrayList();

}

//subject接口的实现

//注册观察者

public void registerObserver(Observer o) {

observers.add(o);

}

//取消注册

public void removeObserver(Observer o) {

int i = observers.indexOf(o);

if (i >= 0) {

observers.remove(i);

}

}

//通知观察者数据改变

public void notifyObservers() {

for (int i = 0; i < observers.size(); i++) {

Observer observer = (Observer)observers.get(i);

observer.update(temperature, humidity, pressure);

}

}

//检测到数据更新时,通知观察者

public void measurementsChanged() {

notifyObservers();

}

public void setMeasurements(float temperature, float humidity, float pressure) {

this.temperature = temperature;

this.humidity = humidity;

this.pressure = pressure;

measurementsChanged();

}

}

5、建立显示当前观测值得布告板

public class CurrentConditionsDisplay implements Observer,DisplayElement{

private float temperature;

private float humidity;

private Subject weatherDate;

public void update(float temperature, float humidity, float pressure) {

this.temperature=temperature;

this.humidity=humidity;

display();

}

public void display() {

System.out.println("Current conditions:"+ temperature+"f degrees and "+humidity+"% humidity");

}

public CurrentConditionsDisplay(Subject weatherDate){

this.weatherDate=weatherDate;

weatherDate.registerObserver(this);

}

}

6、建立根据气压计显示天气预报

public class ForecastDisplay implements Observer, DisplayElement {

private float currentPressure = 29.92f;

private float lastPressure;

private WeatherDate weatherData;

public ForecastDisplay(WeatherDate weatherData) {

this.weatherData = weatherData;

weatherData.registerObserver(this);

}

public void update(float temp, float humidity, float pressure) {

lastPressure = currentPressure;

currentPressure = pressure;

display();

}

public void display() {

System.out.print("Forecast: ");

if (currentPressure > lastPressure) {

System.out.println("Improving weather on the way!");

} else if (currentPressure == lastPressure) {

System.out.println("More of the same");

} else if (currentPressure < lastPressure) {

System.out.println("Watch out for cooler, rainy weather");

}

}

}

7、建立跟踪最小值,平均值,最大的观测值并显示它们的布告板。

public class StatisticsDisplay implements Observer, DisplayElement {

private float maxTemp = 0.0f;

private float minTemp = 200;

private float tempSum= 0.0f;

private int numReadings;

private WeatherDate weatherData;

public StatisticsDisplay(WeatherDate weatherData) {

this.weatherData = weatherData;

weatherData.registerObserver(this);

}

public void update(float temp, float humidity, float pressure) {

tempSum += temp;

numReadings++;

if (temp > maxTemp) {

maxTemp = temp;

}

if (temp < minTemp) {

minTemp = temp;

}

display();

}

public void display() {

System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings)

+ "/" + maxTemp + "/" + minTemp);

}

}

8、建立测试类

public class WeatherSation {

public static void main(String[] args) {

WeatherDate weatherDate=new WeatherDate();

CurrentConditionsDisplay currentDisplay=new CurrentConditionsDisplay(weatherDate);

StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherDate);

ForecastDisplay forecastDisplay=new ForecastDisplay(weatherDate);

weatherDate.setMeasurements(80, 65, 30.4f);

weatherDate.setMeasurements(82, 70, 29.2f);

weatherDate.setMeasurements(78, 90, 29.2f);

}

}

9、运行结果

1.8思维拓展

1、java内置的观察者模式。java.util包内包含最基本的Observer接口与Observable类,利用java内置的观察者模式我们只需要扩展(继承)Observable,并告诉它何时该通知观察者,剩下的API会帮我们做好。

1.9应用场景

1、有多个子类共有的方法,且逻辑相同。

2、存在数据实时更新的情况下。

3、监听器

2.1应用实例

1、报纸和杂志的订阅。

2、拍卖会上,拍卖师观察最高标价,然后,通知其他竞价者。

3、护士将患者每天的检查数据告知患者。

2.2注意事项

1、有多个观察者时,不可以依赖特定的通知次序。(原因:一旦观察者的实现有所改变,通知的次序就会改变,很可能会产生错误的结果。)

2、Java中已经有了对观察者模式支持的类,包括通用的java.util.Observable。

3、避免循环引用。

2.装饰者模式

1.1定义

装饰者模式:动态地将责任附加到对象身上。若要扩展功能,装饰者提供了比继承更有弹性·的替代方案。

1.2 底层机制

利用组合和委托实现在运行时具有继承的效果。我们将装饰者和组件进行组合,就是在加入新的行为,装饰者和组件将更有弹性的加以混合和匹配。

1.3体现的设计原则

1、类应该对扩展开放,对修改关闭。

1.4优缺点

优点:

1、通过动态组合对象,可以写新的代码添加新的功能,而无需修改现有代码。

2、装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

3、可以透明的插入装饰者,客户程序甚至不需要知道在和装饰者打交道。

缺点:

1、多层修饰比较复杂。

2、遵循开放-关闭原则,通常会引入新的抽象层次,增加代码的复杂度。

3、有些代码会依赖特定的类型,而这样的代码一导入装饰者,就出现错误。

4、采用装饰者在实例化组件时,将增加代码的复杂度,一旦使用装饰者模式,不只需要实例化组件,还要把此组件包装进装饰者中。天晓得有几个组件。

 
   

1.5类图

1.6案例:星巴克咖啡

1.6.1类图

1.6.2代码逻辑

1、拿一个咖啡(DarkRoast)对象

2、以摩卡(Mocha)对象装饰它

3、以奶泡(Whip)对象修饰它

4、调用cost()方法。并依赖委托将调料的价钱加上去

1.6.3代码实现

1、实现Beverage类,其为一个抽象类。

public abstract class Beverage {

String description = "Unknown Beverage";

public String getDescription() {

return description;

}

public abstract double cost();

}

2、实现调料CondimentDecorator抽象类,即:装饰者类

public abstract class CondimentDecorator extends Beverage {

public abstract String getDescription();

}

3、写具体组件,饮料类的代码

浓缩咖啡

public class Espresso extends Beverage {

public Espresso() {

description = "Espresso";

}

public double cost() {

return 1.99;

}

}

综合咖啡:

public class HouseBlend extends Beverage {

public HouseBlend() {

description = "House Blend Coffee";

}

public double cost() {

return .89;

}

}

4、编写调料类代码,即具体的装饰者类

摩卡:

public class Mocha extends CondimentDecorator {

Beverage beverage;//用一个实例变量记录被装饰者

//将被装饰者记录到实例变量中

public Mocha(Beverage beverage) {

this.beverage = beverage;

}

public String getDescription() {

return beverage.getDescription() + ", Mocha";

}

public double cost() {

return .20 + beverage.cost();

}

}

奶泡:

public class Whip extends CondimentDecorator {

Beverage beverage;

public Whip(Beverage beverage) {

this.beverage = beverage;

}

public String getDescription() {

return beverage.getDescription() + ", Whip";

}

public double cost() {

return .10 + beverage.cost();

}

}

5、编写测试代码:

public class StarbuzzCoffee {

public static void main(String args[]) {

Beverage beverage = new Espresso();

System.out.println(beverage.getDescription()

+ " $" + beverage.cost());

Beverage beverage2 = new DarkRoast();

beverage2 = new Mocha(beverage2);

beverage2 = new Mocha(beverage2);

beverage2 = new Whip(beverage2);

System.out.println(beverage2.getDescription()

+ " $" + beverage2.cost());

Beverage beverage3 = new HouseBlend();

beverage3 = new Mocha(beverage3);

beverage3 = new Whip(beverage3);

System.out.println(beverage3.getDescription()

+ " $" + beverage3.cost());

}

}

运行结果

java设计模式-观察者模式,装饰者模式的更多相关文章

  1. Java设计模式 - - 单例模式 装饰者模式

    Java设计模式 单例模式 装饰者模式 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 静态代理模式:https://www.cnblogs.com/StanleyBlogs/p/1 ...

  2. Java 设计模式泛谈&装饰者模式和单例模式

    设计模式(Design Pattern) 1.是一套被反复使用.多人知晓的,经过分类编目 的 代码设计经验总结.使用设计模式是为了可重用代码,让代码更容易维护以及扩展. 2.简单的讲:所谓模式就是得到 ...

  3. Java设计模式系列-装饰器模式

    原创文章,转载请标注出处:<Java设计模式系列-装饰器模式> 一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是 ...

  4. 23种java设计模式之装饰者模式及动态代理

    设计模式不管对于何种语言都是存在的,这里介绍的是java的模式 装饰者模式是在二次开发中应用比较多的一款模式,当然了用反射也是可以实现的,今天介绍的是装饰模式,有兴趣的朋友可以自己去了解一下反射是怎么 ...

  5. java设计模式—Decorator装饰者模式

    一.装饰者模式 1.定义及作用 该模式以对客户端透明的方式扩展对象的功能. 2.涉及角色      抽象构件角色:定义一个抽象接口,来规范准备附加功能的类. 具体构件角色:将要被附加功能的类,实现抽象 ...

  6. Java设计模式之装饰者模式

    要实现装饰者模式,注意一下几点内容: 1.装饰者类要实现真实类同样的接口 2.装饰者类内有一个真实对象的引用(可以通过装饰者类的构造器传入) 3.装饰类对象在主类中接受请求,将请求发送给真实的对象(相 ...

  7. java设计模式之七装饰器模式(Decorator)

    顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个 ...

  8. java设计模式之 装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装 ...

  9. Java设计模式之装饰器模式

    1.装饰器模式的定义(保持接口,扩展功能) Decorate装饰器,顾名思义,就是动态的给一个对象添加一些额外的职责,就好比对房子进行装修一样. 2.装饰器模式的特征 具有一个装饰对象. 必须拥有与被 ...

  10. java设计模式之装饰者模式学习

    装饰者模式 Decorator模式(别名Wrapper):动态将职责附加到对象上,若要扩展功能,装饰者提供了比继承更具弹性的代替方案. 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为 ...

随机推荐

  1. [CSS3] 各种角度的三角形绘制

    #triangle-up { width:; height:; border-left: 50px solid transparent; border-right: 50px solid transp ...

  2. RHEL 7 下内存管理小记

    RHEL 7 下内存管理小记 一.Overview 众所周知,在 Linux 操作系统中有三个目录非常有趣好玩. /dev /run /proc 一个个解释下,/dev 用于对特殊设备(BTW:特殊设 ...

  3. 2016级算法期末模拟练习赛-C.AlvinZH的青春记忆II

    1084 AlvinZH的青春记忆II 思路 中等题,二分. 简化题意,一列数字,每秒会自动-1,特殊操作可以使一个数在1s内-k,问这些数都减至0需要多久. 答案肯定在[1,xMax]之间,采用二分 ...

  4. 4. C++11非受限联合体

    在C/C++中,联合体是一种构造类型的数据结构.在一个联合体内,我们可以定义多种不同的数据类型,这些数据类型共享相同的内存空间,可以达到节省内存空间的目的. 1. 取消数据类型的限制 在C++98中, ...

  5. python bytes和str之间的转换

    1 # bytes object 2 b = b"example" 3 4 # str object 5 s = "example" 6 7 # str to ...

  6. linux常见编辑命令

    保存命令 按ESC键 跳到命令模式,然后: :w 保存文件但不退出vi :w file 将修改另外保存到file中,不退出vi :w! 强制保存,不推出vi :wq 保存文件并退出vi :wq! 强制 ...

  7. 洛谷P2051 [AHOI2009]中国象棋(dp)

    题面 luogu 题解 \(50pts:\)显然是\(3\)进制状压\(dp\) \(100pts:\) 一行一行地考虑 \(f[i][j][k]\)表示前\(i\)行,有\(j\)列放了一个,有\( ...

  8. geatpy - 遗传和进化算法相关算子的库函数(python)

    Geatpy The Genetic and Evolutionary Algorithm Toolbox for Python Introduction Website (including doc ...

  9. linux ln 命令,相当于windows快捷方式

    ln -s 源文件 目标文件. ln -s  **  **,它只会在你选定的位置上生成一个文件的镜像,不会占用磁盘空间, 硬链接ln ** **,没有参数-s, 它会在你选定的位置上生成一个和源文件大 ...

  10. 参数化测试与Mock

    参数化测试与Mock 转载自https://blog.csdn.net/sunliduan/article/details/42026509 单元测试概念 说到测试,大家都不会陌生,从我们开始学习编程 ...