0
点赞
收藏
分享

微信扫一扫

观察者模式(发布-订阅)


由于网站带有弱sns功能,因此需要设计关注和被关注的消息或是动作通知,那么将这个需求抽象出来的时候就会发现正好符合java中发布订阅模式。

一、概述 
Java 的设计模式很多,观察者模式被称为是模式中的皇后,而且Java jdk也对它做了实现,可见该设计模式的重要位置。在图形化设计的软件中,为了实现视图和事件处理的分离,大多都采用了Observer模式,比如 Java的Swing,Flex的ActionScript等。在现实的应用系统中也有好多应用,比如像当当网、京东商城一类的电子商务网站,如果你对某 件商品比较关注,可以放到收藏架,那么当该商品降价时,系统给您发送站内消息、手机短信、邮件。这就是观察者模式的一个典型应用,商品是被观察者,关注该商品的客户 就是观察者。

GoF说道:Observer模式的意图是“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。参见下图:

观察者模式(发布-订阅)_User


可以看出来,观察者模式,是一种一对多的关系,即多个观察者监听一个主题。

 

二、示例代码

商品价格打折后,所有关注、收藏该商品的用户都收到相关的信息提醒。

角色:

1)商品:被观察者;

2)用户:观察者

 

1.商品(发布者)

 


    1. import
    2. import
    3. import
    4.     
    5. /** 
    6.  * 商品-发布者 
    7.  * @author Administrator 
    8.  * 
    9.  */
    10. public class
    11. private
    12. private double
    13. private List<Observer> focusUsers;//观察者集合  
    14.         
    15. /** 
    16.      * 价格折扣 
    17.      * @param off 
    18.      */
    19. public synchronized void payOff(double
    20. this.price = getPrice() * (1
    21. null;    
    22.             
    23. if(focusUsers != null
    24.             Iterator it = focusUsers.iterator();    
    25. while(it.hasNext()){    
    26.                 Observer user = (Observer)it.next();    
    27.                     
    28. ", "+ this.getName() +"的价格 "+ this.getPrice() +", 价格折扣 "+ off * 100 +"%!";    
    29. new
    30. "~~~~ 您好 "+ user.getName());    
    31.                 msg.append(msgPart);    
    32.                     
    33. //发送提醒  
    34.             }    
    35.         }    
    36.     }    
    37.         
    38. /** 
    39.      * 添加关注用户 
    40.      * @param user 
    41.      */
    42. public void
    43. this.getFocusUsers().add(user);    
    44.     }    
    45. /** 
    46.      * 删除关注用户 
    47.      * @param user 
    48.      */
    49. public void
    50. this.getFocusUsers().remove(user);    
    51.     }    
    52.         
    53.         
    54. public
    55. new
    56.     }    
    57.         
    58. public
    59. return
    60.     }    
    61. public void
    62. this.name = name;    
    63.     }    
    64. public double
    65. return
    66.     }    
    67. public void setPrice(double
    68. this.price = price;    
    69.     }    
    70.         
    71.         
    72. public
    73. return
    74.     }    
    75. public void
    76. this.focusUsers = focusUsers;    
    77.     }    
    78.         
    79. }


     

     

    2.观察者(订阅者)接口

     


      1. /** 
      2.  * 观察者(订阅者)接口 
      3.  * @author Administrator 
      4.  * 
      5.  */
      6. public interface
      7.         
      8. public void
      9.         
      10. public
      11.         
      12. }

      3.观察者(订阅者)

       

      1. import
      2.     
      3. /** 
      4.  * 观察者(订阅者) 
      5.  * @author Administrator 
      6.  * 
      7.  */
      8. public class User implements
      9. private
      10. private
      11.         
      12. /** 
      13.      * 通知方法 
      14.      */
      15. public void
      16.         System.out.println(msg);    
      17.     }    
      18.         
      19. public
      20. new
      21.     }    
      22.         
      23. public
      24. return
      25.     }    
      26. public void
      27. this.name = name;    
      28.     }    
      29. public
      30. return
      31.     }    
      32. public void
      33. this.focusPdts = focusPdts;    
      34.     }       
      35.         
      36. }

       

       

      4.client端调用

       


        1. public class
        2.     
        3. /** 
        4.      * @param args 
        5.      */
        6. public static void
        7. //产品  
        8. new
        9. "SAMSUNG手机");    
        10. 2000);    
        11.             
        12. new
        13. "JAVA设计模式");    
        14. 80);    
        15.             
        16. //用户  
        17. new
        18. "张三");    
        19. //关注某一款三星手机  
        20. //user1.getFocusPdts().add(book);//关注JAVA设计模式  
        21.             
        22. new
        23. "李四");    
        24. //关注某一款三星手机  
        25. //关注JAVA设计模式  
        26.             
        27. //建立商品和订阅者关联  
        28.         mobile.getFocusUsers().add(user1);    
        29.         book.getFocusUsers().add(user1);    
        30.         book.getFocusUsers().add(user2);    
        31.             
        32. //产品打折,发送站内信提醒  
        33. 0.1);    
        34. 0.2);    
        35.     }    
        36.     
        37. }

         

        三、功能设计

        常用的处理方式:

        将数据库作为数据存储的介质,消息提醒数据保存在数据库表中,采用定时任务的方式来汇总和发送。具体流程:

        1.存储用户-关注关联数据

        将用户和所关注的数据存储到一张“用户-关注商品关联表”;

         

        2.执行汇总任务

        商品打折时,触发汇总任务,遍历“用户-关注商品“关联表,将符合发送条件的记录汇总到”提醒消息表“;数据量巨大的情况下,可采用在“用户-关注商品关联表”冗余字段的方式,不再创建”提醒消息表“减小数据量。

         

        3.发送折扣提醒消息

        遍历”提醒消息表“并发送,发送完成后,将记录标示为已发送。

         

        四、设计分析

        如果系统的用户、商品数量都很大,这种情况下如何设计功能更合理呢,个人认为有几点需要关注:

        1)响应及时性

        2)数据的持久性

        3)web层压力

        4)数据库层压力

        5)系统资源的消耗

         

        内存方式:   采用观察者模式,将关注用户保存在商品对象中,也就是存储在java 堆中。

        数据库方式:采用传统关系型数据,例如mysql等。

         

         


        项目

        内存

        数据库

        分析

        响应及时性

        较好

        较差

        内存操作比起数据库操作肯定性能上好很多

        数据的持久性

        较差

        较好

        如果出现宕机等故障,内存数据会被清空,导致整个功能异常。

        所以说数据仅保存在内存有缺陷,将内存数据持久化到数据库中做备份是较完备的方案,具体实现暂不讨论。

        web层压力

        较大

        中等

        由于用户和商品数量巨大,商品-内存关联数据保存在内存中对系统内存消耗较大,假如1000W用户,每个用户关注10个商品的话,每条记录100Byte,那么大致占用10G左右,直觉上对内存占用较大,会影响整个系统的表现。

        数据库层压力

        较大

        用户-商品关注关联表,约1亿条数据。发送提醒消息和更改发送标示需要1次读操作、1次写操作,对数据的存储和数据库的压力都是一个挑战。另外,实现上肯定要采用缩小每次读写操作的数据集的方式。

        系统资源消耗

        中等

        中等

        内存方式,对系统内存占用较大,但对其他系统资源消耗不大。数据库方式,对系统的数据库层有较大的压力。


         

        通过以上分析,发现两种方式都有比较大的问题,那是否可以采用key-value型内存软件加持久数据到数据库中的方式来实现呢?


        1)key-value型内存操作比直接数据库操作(磁盘io)操作性能上好很多;
        2)将内存数据保存1份到数据库应对内存失效问题,采用异步持久化方式可减小对系统整体资源的消耗。

        举报

        相关推荐

        0 条评论