java设计模式-观察者模式,装饰者模式
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设计模式-观察者模式,装饰者模式的更多相关文章
- Java设计模式 - - 单例模式 装饰者模式
Java设计模式 单例模式 装饰者模式 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 静态代理模式:https://www.cnblogs.com/StanleyBlogs/p/1 ...
- Java 设计模式泛谈&装饰者模式和单例模式
设计模式(Design Pattern) 1.是一套被反复使用.多人知晓的,经过分类编目 的 代码设计经验总结.使用设计模式是为了可重用代码,让代码更容易维护以及扩展. 2.简单的讲:所谓模式就是得到 ...
- Java设计模式系列-装饰器模式
原创文章,转载请标注出处:<Java设计模式系列-装饰器模式> 一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是 ...
- 23种java设计模式之装饰者模式及动态代理
设计模式不管对于何种语言都是存在的,这里介绍的是java的模式 装饰者模式是在二次开发中应用比较多的一款模式,当然了用反射也是可以实现的,今天介绍的是装饰模式,有兴趣的朋友可以自己去了解一下反射是怎么 ...
- java设计模式—Decorator装饰者模式
一.装饰者模式 1.定义及作用 该模式以对客户端透明的方式扩展对象的功能. 2.涉及角色 抽象构件角色:定义一个抽象接口,来规范准备附加功能的类. 具体构件角色:将要被附加功能的类,实现抽象 ...
- Java设计模式之装饰者模式
要实现装饰者模式,注意一下几点内容: 1.装饰者类要实现真实类同样的接口 2.装饰者类内有一个真实对象的引用(可以通过装饰者类的构造器传入) 3.装饰类对象在主类中接受请求,将请求发送给真实的对象(相 ...
- java设计模式之七装饰器模式(Decorator)
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下: Source类是被装饰类,Decorator类是一个 ...
- java设计模式之 装饰器模式
装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装 ...
- Java设计模式之装饰器模式
1.装饰器模式的定义(保持接口,扩展功能) Decorate装饰器,顾名思义,就是动态的给一个对象添加一些额外的职责,就好比对房子进行装修一样. 2.装饰器模式的特征 具有一个装饰对象. 必须拥有与被 ...
- java设计模式之装饰者模式学习
装饰者模式 Decorator模式(别名Wrapper):动态将职责附加到对象上,若要扩展功能,装饰者提供了比继承更具弹性的代替方案. 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为 ...
随机推荐
- [CSS3] 各种角度的三角形绘制
#triangle-up { width:; height:; border-left: 50px solid transparent; border-right: 50px solid transp ...
- RHEL 7 下内存管理小记
RHEL 7 下内存管理小记 一.Overview 众所周知,在 Linux 操作系统中有三个目录非常有趣好玩. /dev /run /proc 一个个解释下,/dev 用于对特殊设备(BTW:特殊设 ...
- 2016级算法期末模拟练习赛-C.AlvinZH的青春记忆II
1084 AlvinZH的青春记忆II 思路 中等题,二分. 简化题意,一列数字,每秒会自动-1,特殊操作可以使一个数在1s内-k,问这些数都减至0需要多久. 答案肯定在[1,xMax]之间,采用二分 ...
- 4. C++11非受限联合体
在C/C++中,联合体是一种构造类型的数据结构.在一个联合体内,我们可以定义多种不同的数据类型,这些数据类型共享相同的内存空间,可以达到节省内存空间的目的. 1. 取消数据类型的限制 在C++98中, ...
- python bytes和str之间的转换
1 # bytes object 2 b = b"example" 3 4 # str object 5 s = "example" 6 7 # str to ...
- linux常见编辑命令
保存命令 按ESC键 跳到命令模式,然后: :w 保存文件但不退出vi :w file 将修改另外保存到file中,不退出vi :w! 强制保存,不推出vi :wq 保存文件并退出vi :wq! 强制 ...
- 洛谷P2051 [AHOI2009]中国象棋(dp)
题面 luogu 题解 \(50pts:\)显然是\(3\)进制状压\(dp\) \(100pts:\) 一行一行地考虑 \(f[i][j][k]\)表示前\(i\)行,有\(j\)列放了一个,有\( ...
- geatpy - 遗传和进化算法相关算子的库函数(python)
Geatpy The Genetic and Evolutionary Algorithm Toolbox for Python Introduction Website (including doc ...
- linux ln 命令,相当于windows快捷方式
ln -s 源文件 目标文件. ln -s ** **,它只会在你选定的位置上生成一个文件的镜像,不会占用磁盘空间, 硬链接ln ** **,没有参数-s, 它会在你选定的位置上生成一个和源文件大 ...
- 参数化测试与Mock
参数化测试与Mock 转载自https://blog.csdn.net/sunliduan/article/details/42026509 单元测试概念 说到测试,大家都不会陌生,从我们开始学习编程 ...