观察者模式(公布-订阅)(转载含实例)
观察者模式(发布-订阅)(转载含实例)一、概述?Java 的设计模式很多,观察者模式被称为是模式中的皇后,而且Jav
观察者模式(发布-订阅)(转载含实例)
一、概述?
Java 的设计模式很多,观察者模式被称为是模式中的皇后,而且Java jdk也对它做了实现,可见该设计模式的重要位置。在图形化设计的软件中,为了实现视图和事件处理的分离,大多都采用了Observer模式,比如 Java的Swing,Flex的ActionScript等。在现实的应用系统中也有好多应用,比如像当当网、京东商城一类的电子商务网站,如果你对某 件商品比较关注,可以放到收藏架,那么当该商品降价时,系统给您发送站内消息、手机短信、邮件。这就是观察者模式的一个典型应用,商品是被观察者,关注该商品的客户 就是观察者。
GoF说道:Observer模式的意图是“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。参见下图:

可以看出来,观察者模式,是一种一对多的关系,即多个观察者监听一个主题。
?
二、示例代码
商品价格打折后,所有关注、收藏该商品的用户都收到相关的信息提醒。
角色:
1)商品:被观察者;
2)用户:观察者
?
1.商品(发布者)
?
Java代码??

- import?java.util.ArrayList;????
- import?java.util.Iterator;????
- import?java.util.List;????
- ????
- /**??
- ?*?商品-发布者??
- ?*?@author?Administrator??
- ?*??
- ?*/????
- public?class?Product?{????
- ????private?String?name;????
- ????private?double?price;????
- ????private?List<Observer>?focusUsers;//观察者集合????
- ????????
- ????/**??
- ?????*?价格折扣??
- ?????*?@param?off??
- ?????*/????
- ????public?synchronized?void?payOff(double?off){????
- ????????this.price?=?getPrice()?*?(1?-?off);????????????
- ????????StringBuffer?msg?=?null;????
- ????????????
- ????????if(focusUsers?!=?null?&&?!focusUsers.isEmpty()){????
- ????????????Iterator?it?=?focusUsers.iterator();????
- ????????????while(it.hasNext()){????
- ????????????????Observer?user?=?(Observer)it.next();????
- ????????????????????
- ????????????????String?msgPart?=?",?"+?this.getName()?+"的价格?"+?this.getPrice()?+",?价格折扣?"+?off?*?100?+"%!";????
- ????????????????msg?=?new?StringBuffer();????
- ????????????????msg.append("~~~~?您好?"+?user.getName());????
- ????????????????msg.append(msgPart);????
- ????????????????????
- ????????????????user.notify(msg.toString());//发送提醒????
- ????????????}????
- ????????}????
- ????}????
- ????????
- ????/**??
- ?????*?添加关注用户??
- ?????*?@param?user??
- ?????*/????
- ????public?void?addFocusUsers(User?user)?{????
- ????????this.getFocusUsers().add(user);????
- ????}????
- ????/**??
- ?????*?删除关注用户??
- ?????*?@param?user??
- ?????*/????
- ????public?void?delFocusUser(User?user)?{????
- ????????this.getFocusUsers().remove(user);????
- ????}????
- ????????
- ????????
- ????public?Product(){????
- ????????focusUsers?=?new?ArrayList<Observer>();????
- ????}????
- ????????
- ????public?String?getName()?{????
- ????????return?name;????
- ????}????
- ????public?void?setName(String?name)?{????
- ????????this.name?=?name;????
- ????}????
- ????public?double?getPrice()?{????
- ????????return?price;????
- ????}????
- ????public?void?setPrice(double?price)?{????
- ????????this.price?=?price;????
- ????}????
- ????????
- ????????
- ????public?List<Observer>?getFocusUsers()?{????
- ????????return?focusUsers;????
- ????}????
- ????public?void?setFocusUsers(List<Observer>?focusUsers)?{????
- ????????this.focusUsers?=?focusUsers;????
- ????}????
- ????????
- }????
?
?
2.观察者(订阅者)接口
?
Java代码??

- /**??
- ?*?观察者(订阅者)接口??
- ?*?@author?Administrator??
- ?*??
- ?*/????
- public?interface?Observer?{????
- ????????
- ????public?void?notify(String?msg);????
- ????????
- ????public?String?getName();????
- ????????
- }????
?
?
3.观察者(订阅者)
?
Java代码??

- import?java.util.HashSet;????
- import?java.util.Set;????
- ????
- /**??
- ?*?观察者(订阅者)??
- ?*?@author?Administrator??
- ?*??
- ?*/????
- public?class?User?implements?Observer?{????
- ????private?String?name;????
- ????private?Set<Product>?focusPdts;????
- ????????
- ????/**??
- ?????*?通知方法??
- ?????*/????
- ????public?void?notify(String?msg){????
- ????????System.out.println(msg);????
- ????}????
- ????????
- ????public?User(){????
- ????????focusPdts?=?new?HashSet<Product>();????
- ????}????
- ????????
- ????public?String?getName()?{????
- ????????return?name;????
- ????}????
- ????public?void?setName(String?name)?{????
- ????????this.name?=?name;????
- ????}????
- ????public?Set<Product>?getFocusPdts()?{????
- ????????return?focusPdts;????
- ????}????
- ????public?void?setFocusPdts(Set<Product>?focusPdts)?{????
- ????????this.focusPdts?=?focusPdts;????
- ????}???????
- ????????
- }???
?
?
4.client端调用
?
Java代码??

- public?class?client?{????
- ????
- ????/**??
- ?????*?@param?args??
- ?????*/????
- ????public?static?void?main(String[]?args)?{????
- ????????//产品????
- ????????Product?mobile?=?new?Product();????
- ????????mobile.setName("SAMSUNG手机");????
- ????????mobile.setPrice(2000);????
- ????????????
- ????????Product?book?=?new?Product();????
- ????????book.setName("JAVA设计模式");????
- ????????book.setPrice(80);????
- ????????????
- ????????//用户????
- ????????User?user1?=?new?User();????
- ????????user1.setName("张三");????
- ????????user1.getFocusPdts().add(mobile);//关注某一款三星手机????
- ????????//user1.getFocusPdts().add(book);//关注JAVA设计模式????
- ????????????
- ????????User?user2?=?new?User();????
- ????????user2.setName("李四");????
- ????????user2.getFocusPdts().add(mobile);//关注某一款三星手机????
- ????????user2.getFocusPdts().add(book);//关注JAVA设计模式????
- ????????????
- ????????//建立商品和订阅者关联????
- ????????mobile.getFocusUsers().add(user1);????
- ????????book.getFocusUsers().add(user1);????
- ????????book.getFocusUsers().add(user2);????
- ????????????
- ????????//产品打折,发送站内信提醒????
- ????????mobile.payOff(0.1);????
- ????????book.payOff(0.2);????
- ????}????
- ????
- }????
?
?
三、功能设计
常用的处理方式:
将数据库作为数据存储的介质,消息提醒数据保存在数据库表中,采用定时任务的方式来汇总和发送。具体流程:
1.存储用户-关注关联数据
将用户和所关注的数据存储到一张“用户-关注商品关联表”;
?
2.执行汇总任务
商品打折时,触发汇总任务,遍历“用户-关注商品“关联表,将符合发送条件的记录汇总到”提醒消息表“;数据量巨大的情况下,可采用在“用户-关注商品关联表”冗余字段的方式,不再创建”提醒消息表“减小数据量。
?
3.发送折扣提醒消息
遍历”提醒消息表“并发送,发送完成后,将记录标示为已发送。
?
四、设计分析
如果系统的用户、商品数量都很大,这种情况下如何设计功能更合理呢,个人认为有几点需要关注:
1)响应及时性
2)数据的持久性
3)web层压力
4)数据库层压力
5)系统资源的消耗
?
内存方式:?? 采用观察者模式,将关注用户保存在商品对象中,也就是存储在java 堆中。
数据库方式:采用传统关系型数据,例如mysql等。
?
?
项目
内存
数据库
分析
内存方式,对系统内存占用较大,但对其他系统资源消耗不大。数据库方式,对系统的数据库层有较大的压力。
?
通过以上分析,发现两种方式都有比较大的问题,那是否可以采用key-value型内存软件加持久数据到数据库中的方式来实现呢?
1)key-value型内存操作比直接数据库操作(磁盘io)操作性能上好很多;
2)将内存数据保存1份到数据库应对内存失效问题,采用异步持久化方式可减小对系统整体资源的消耗。原帖地址:http://qify.iteye.com/blog/1921919?附件为本人自己写的小例子