zoukankan      html  css  js  c++  java
  • WUST 设计模式 实验九 观察者模式的应用

    实验九 观察者模式的应用

    一、实验目的

    1. 掌握外观模式(Observer)的特点;
    2. 分析具体问题,使用外观模式进行设计。

    二、实验内容和要求

      网上商店中如果商品(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例题差太远了,,,哎,心累。实际上,ObservableObserver是没有实际意义的,主要是起到一个松耦合的作用,我开始一直按照PPT给的例题那样将它赋予实际意义,结果发现无论怎么想都不对,我只能说例题真特殊。Java的JDK中有已经写好的Observer类和Observable类,代码不是很难,可以学学。非常有益。


    写在最后:

    1. 如需转载,请于首页至少注明链接形式的wowpH的博客这几个字;
    2. 代码原创,如需公开引用,不能删除首行注释(作者,版本号,时间等信息)。
    3. 如果有疑问欢迎评论留言,尽量解答。

  • 相关阅读:
    ActiveReports中如何在后台导出运行时绑定数据源报表
    ActiveReports中如何控制页面的记录数
    WordPress建站固定链接问题
    Linux环境下使用g++编译C++
    Git diff结果显示分析
    VTK使用过程中遇到的问题
    右值引用、移动语义和完美转发(下)
    右值引用、移动语义和完美转发(中)
    右值引用、移动语义和完美转发(上)
    new和malloc的联系与区别(下)
  • 原文地址:https://www.cnblogs.com/wowpH/p/11060806.html
Copyright © 2011-2022 走看看