WUST 设计模式 实验九 观察者模式的应用
实验九 观察者模式的应用
一、实验目的
- 掌握外观模式(Observer)的特点;
- 分析具体问题,使用外观模式进行设计。
二、实验内容和要求
网上商店中如果商品(product)在名称(name)、价格(price)等方面有变化,系统能自动通知会员,将是网上商店区别传统商店的一大特色。如何设计实现? 说明你所选择的设计模式,画出类关系图并指明各个类的角色。应用外观模式,用C#控制台应用程序改进该设计。绘制该模式的UML图。
三、实验环境
编译环境:Windows 10
编译工具:Eclipse IDE
UML图工具:StarUML 3.1
四、源程序
/**
* 被观察目标
*
* @author PengHao
* @version 1.0
* @date 2019年4月28日 下午3:03:44
*/
import java.util.Vector;
public abstract class Observable {
/**
* @Field obs 观察者集合
*/
private Vector<Observer> obs;
/**
* 构造方法,创建一个空的集合
*/
public Observable() {
obs = new Vector<>();
}
/**
* 添加观察者对象
*
* @param o 要添加的观察者对象
*/
public synchronized void addObserver(Observer o) {
if (null == o) { // 如果是空,抛出Null异常
throw new NullPointerException();
}
if (!obs.contains(o)) { // 如果集合中没有这个对象
obs.addElement(o); // 添加这个对象
}
}
/**
* 删除观察者对象
*
* @param o 要删除观察者对象
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o); // 从集合中移除
}
/**
* 通知当前目标的所有观察者
*
* @param message 更改的信息,打包发给会员
*/
public void notifyObservers(String message) {
Object[] arrLocal;
arrLocal = obs.toArray();
for (Object object : arrLocal) {
((Observer) object).update(message); // 调用观察者的更新方法
}
}
}
/**
* 产品类,被观察的具体目标
*
* @author PengHao
* @version 1.0
* @date 2019年4月28日 下午3:11:41
*/
public class Product extends Observable {
/**
* @Field name 产品名称
*/
private String name;
/**
* @Field price 产品价格
*/
private double price;
/**
* 创建新的产品
*
* @param name 产品名称
* @param price 产品价格
*/
public Product(String name, double price) {
this.name = name;
this.price = price;
}
/**
* 订购当前产品
*/
public void addObserver(Observer o) {
System.out.print(((Member) o).getName());
System.out.println("订购" + name + "成功"); // 提示订购信息
super.addObserver(o); // 调用父类的添加方法
}
/**
* 取消订购当前产品
*/
public void deleteObserver(Observer o) {
System.out.print(((Member) o).getName());
System.out.println("已取消订购" + name); // 提示取消订购信息
super.deleteObserver(o); // 调用父类的删除方法
}
/**
* 设置产品名称,通知所有的具体观察者(会员)
*
* @param name 产品新的名称
*/
public void setName(String name) {
// 名称一样就不用通知
if (!this.name.contentEquals(name)) {
StringBuilder message = new StringBuilder();
message.append(this.name).append("的名称已从").append(this.name);
this.name = name; // 设置新的名称
message.append("更改为").append(this.name);
notifyObservers(message.toString()); // 通知会员
}
}
/**
* 设置产品价格,通知所有具体观察者(会员)
*
* @param price 产品新的价格
*/
public void setPrice(double price) {
// 价格相同,就不用通知
if (this.price != price) {
StringBuilder message = new StringBuilder();
message.append(name).append("的价格已从");
message.append(this.price).append("元");
this.price = price;
message.append("更改为").append(this.price);
message.append("元");
notifyObservers(message.toString()); // 通知会员
}
}
}
/**
* 观察者接口,要实现update方法
*
* @author PengHao
* @version 1.0
* @date 2019年4月28日 下午3:11:05
*/
public interface Observer {
/**
* 通知会员
*
* @param message 通知的消息
*/
void update(String message);
}
/**
* 会员
*
* @author PengHao
* @version 1.0
* @date 2019年4月28日 下午3:18:59
*/
public class Member implements Observer {
/**
* @Field name 会员名字
*/
private String name;
/**
* @Field product 会员订购的产品
*/
private Product product = null;
/**
* 构造方法,创建一个具有姓名的会员,可以不订购产品
*
* @param name 会员姓名
*/
public Member(String name) {
this(name, null);
}
/**
* 构造方法,创建一个订购了产品的会员
*
* @param name 会员姓名
* @param product 会员订购的产品
*/
public Member(String name, Product product) {
this.name = name;
if (null != product) {
this.product = product;
/**
* 将当前会员添加到产品product的观察者列表中去,为了以后通知
*/
product.addObserver(this);
}
}
/**
* 更新信息,通知会员
*/
@Override
public void update(String message) {
System.out.println("尊敬的会员" + name + "您好!");
System.out.println(message);
}
/**
* @param product 修改订购的产品
*/
public void setProduct(Product product) {
if (null != this.product) { // 原来已经订购了产品
/**
* 将当前会员从原来的产品会员列表删除
*/
this.product.deleteObserver(this);
}
this.product = product;
/**
* 将当前会员添加到新的产品会员列表中
*/
product.addObserver(this);
}
/**
* 取消订购产品
*/
public void clearProduct() {
if (null != product) {
product.deleteObserver(this); // 从列表移除
this.product = null;
}
}
/**
* @return 会员姓名
*/
public String getName() {
return name;
}
}
/**
* 客户端类(测试类)
* @author PengHao
* @version 1.0
* @date 2019年4月28日 下午5:01:23
*/
public class Client {
public static void main(String[] args) {
Product milk = new Product("牛奶", 2.50); // 牛奶
Member ph = new Member("PH", milk); // ph订牛奶
Member pc = new Member("PC"); // 暂不订购牛奶
pc.setProduct(milk); // pc订购牛奶
System.out.println();
milk.setName("纯牛奶"); // 牛奶改名字
System.out.println();
pc.clearProduct(); // pc退订牛奶
System.out.println();
milk.setPrice(3.00); // 牛奶涨价
System.out.println();
Product yogurt = new Product("酸奶", 6.0); // 可乐
ph.setProduct(yogurt); // ph订酸奶
pc.setProduct(yogurt); // pc订酸奶
System.out.println();
milk.setName("伊利纯牛奶"); // 牛奶改名字
System.out.println();
yogurt.setPrice(5.50); // 酸奶降价
}
}
五、UML图

六、运行截图

七、小结(交报告)
观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察者模式支持广播通信。观察者模式符合“开闭原则”的要求。
总结
这个模式我服了,一开始就理解错了方向,感觉跟PPT例题差太远了,,,哎,心累。实际上,Observable和Observer是没有实际意义的,主要是起到一个松耦合的作用,我开始一直按照PPT给的例题那样将它赋予实际意义,结果发现无论怎么想都不对,我只能说例题真特殊。Java的JDK中有已经写好的Observer类和Observable类,代码不是很难,可以学学。非常有益。
写在最后:
- 如需转载,请于首页至少注明链接形式的wowpH的博客这几个字;
- 代码原创,如需公开引用,不能删除首行注释(作者,版本号,时间等信息)。
- 如果有疑问欢迎评论留言,尽量解答。
WUST 设计模式 实验九 观察者模式的应用的更多相关文章
- WUST 设计模式 实验一 单例模式的应用
实验一 单例模式的应用 实验目的 1.掌握单例模式(Singleton)的特点: 2.分析具体问题,使用单例模式进行设计. 实验内容和要求 很多应用项目都有配置文件,这些配置文件里面定义一些应用需要的 ...
- Linux基础入门(新版)(实验九-实验十二)
实验九 简单文本入门 一.常用的文本处理命令 二.文本处理命令 1.tr 命令 tr 命令可以用来删除一段文本信息中的某些文字.或者将其进行转换. 使用方式: tr [option]...SET1 [ ...
- 设计模式 ( 十九 ) 模板方法模式Template method(类行为型)
设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行 ...
- 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)
设计模式 ( 十六 ) 观察者模式Observer(对象行为型) 1.概述 一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力.当对象们连接在一起时,它们就可以相互提供服务和信息. 通常来 ...
- 设计模式(九)外观模式Facade(结构型)
设计模式(九)外观模式Facade(结构型) 1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性. ...
- Java设计模式之《观察者模式》及应用场景
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6513651.html 观察者模式,又可以称之为发布-订阅模式,观察者,顾名思义,就是一个监 ...
- 2017-2018-2 20155228 《网络对抗技术》 实验九:Web安全基础
2017-2018-2 20155228 <网络对抗技术> 实验九:Web安全基础 1. 实践内容 1.1 标理解常用网络攻击技术的基本原理 1.2 在Webgoat实验环境下实践相关实验 ...
- 实验九 ZStack 广播通信实验
实验九 ZStack 广播通信实验[实验目的]1. 了解 ZigBee 广播通信的原理2. 掌握在 ZigBee 网络中进行广播通信的方法[实验设备]1. 装有 IAR 开发工具的 PC 机一台2. ...
- 2017-2018-2 20155225《网络对抗技术》实验九 Web安全基础
2017-2018-2 20155225<网络对抗技术>实验九 Web安全基础 WebGoat 1.String SQL Injection 题目是想办法得到数据库所有人的信用卡号,用Sm ...
随机推荐
- Android Studio如何删除一个Module
当你想在Android Studio中删除某个module时,大家习惯性的做法都是选中要删除的module,右键去找delete.但是在Android Studio中你选中module,右键会发现没 ...
- IdentityServer4入门三:授权模式
在入门一.入门二我们实现了一个完整的API保护的过程.需要保护的API只需在其Controler上应用[Authorize]特性,来显式指定受保护的资源.而我们实现的这个例子,所应用的模式叫“Clie ...
- 可视化图表库--goJS
GoJS是Northwoods Software的产品.Northwoods Software创立于1995年,专注于交互图控件和类库.旗下四款产品: GoJS:用于在HTML上创建交互图的纯java ...
- 感知机模型到DNN模型
参考资料 感知机模型:https://www.cnblogs.com/pinard/p/6042320.html DNN:https://www.cnblogs.com/pinard/p/641866 ...
- LuaJIT 之 FFI
1. FFI 教程 原文: FFI Tutorial 相关链接:OpenResty 最佳实践之 FFI 加载 FFI 库 FFI 库时默认编译进 LuaJIT 中的,但是不会默认加载或初始化.因此,当 ...
- [GitHub]纪华裕的GitHub收藏
由于GitHub的star没有分类功能在此写下我的收藏. JS nodenodejs的仓库 puppeteer一个用户测试的无头浏览器 moment日期操作库,包括格式化等
- mysql 触发器语法详解
1.创建Mysql触发器: 语法: CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW BE ...
- NetHogs监控Linux的每个进程流量
在日常运维环境中,我们肯定会遇到以下这种需求: 1.网络流量异常,不知道是哪个程序的流量爆涨? 2.日常需要监控网络实时的流量进去数据 面试装逼系列|这篇文章,让运维监控不再成为你的短板! 学会这 1 ...
- Qt编写自定义控件59-直方动态图
一.前言 直方动态图类似于音乐播放时候的柱状图展示,顶部提供一个横线条,当柱状上升的时候,该线条类似于帽子的形式冲到顶端,相当于柱状顶上去的感觉,给人一种动态的感觉,听音乐的同时更加赏心悦目,原理比较 ...
- java@ 注解原理与使用
Java反射 java反射机制的定义: 在运行转态时(动态的)时. 对于任意一个类,都能够知道这个类的所有属性和方法 对于任意一个对象,都能够知道调用它的任意属性和方法 Class对象 java中用对 ...