• (C语言进阶)设计模式之--观察者模式


    • 定义

    观察者是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个“观察”该对象的其他对象。

    假如你有两种类型的对象: 顾客 和 商店 。顾客对某个特定品牌的产品非常感兴趣(例如最新型号的 iPhone 手机),而该产品很快将会在商店里出售。顾客可以每天来商店看看产品是否到货。但如果商品尚未到货时,绝大多数来到商店的顾客都会空手而归。

     另一方面,每次新产品到货时,商店可以向所有顾客发送邮件(可能会被视为垃圾邮件)。这样,部分顾客就无需反复前往商店了,但也可能会惹恼对新产品没有兴趣的其他顾客。我们似乎遇到了一个矛盾:要么让顾客浪费时间检查产品是否到货,要么让商店浪费资源去通知没有需求的顾客。

    拥有一些值得关注的状态的对象通常被称为目标,由于它要将自身的状态改变通知给其他对象,我们也将其称为发布者(publisher)。

    所有希望关注发布者状态变化的其他对象被称为订阅者(subscribers)。

    观察者模式建议你为发布者类添加订阅机制,让每个对象都能订阅或取消订阅发布者事件流。不要害怕!这并不像听上去那么复杂。实际上,该机制包括:

    1)一个用于存储订阅者对象引用的列表成员变量;

    2)几个用于添加或删除该列表中订阅者的公有方法。

    •  代码实现
    1. #ifndef _OBSERVER_H_
    2. #define _OBSERVER_H_
    3. typedef struct
    4. {
    5. void (*update_Audio_date)(int *audio_buf);
    6. }interfaces_update_Audio_t;
    7. typedef struct
    8. {
    9. void (*update_video_date)(int *video_buf);
    10. }interfaces_update_Video_t;
    11. #endif
    1. #include "stdio.h"
    2. #include "string.h"
    3. #include
    4. #include "Observer.h"
    5. #define OBSERVER_MAX_COUNT 10
    6. Observer Audio_Observer;
    7. Observer Video_Observer;
    8. typedef struct observer
    9. {
    10. void (*update)(int *buf);
    11. }Observer;
    12. typedef struct subject
    13. {
    14. Observer *array_observer[OBSERVER_MAX_COUNT];
    15. int (*register_observer)(Observer *observer);
    16. int (*remove_observer)(Observer *observer);
    17. void (*notify_observer)(int *buf);
    18. //void (*other_function)(void);
    19. }Subject;
    20. Subject SwitchBot_Subject;
    21. static int observer_count=0;
    22. void update_video_date(int *buf)
    23. {
    24. //do video function
    25. }
    26. void update_audio_date(int *buf)
    27. {
    28. //do audio fuction
    29. }
    30. int woan_register_observer(Observer *observer)
    31. {
    32. if(observer_count>=OBSERVER_MAX_COUNT)
    33. return 0;
    34. SwitchBot_Subject.array_observer[observer_count++]=observer;
    35. return 1;
    36. }
    37. int woan_remove_observer(Observer *observer)
    38. {
    39. int i=0;
    40. for(i=0;i
    41. {
    42. if(observer==SwitchBot_Subject.array_observer[i])
    43. {
    44. SwitchBot_Subject.array_observer[i]=0;
    45. break;
    46. }
    47. }
    48. return 1;
    49. }
    50. void woan_notify_observer(int *buf)
    51. {
    52. int i=0;
    53. Observer *observer=0;
    54. for(i=0;i
    55. {
    56. observer=SwitchBot_Subject.array_observer[i];
    57. if(observer!=0)
    58. observer->update(buf);
    59. }
    60. }
    61. void init_switchbot_subject()
    62. {
    63. int i=0;
    64. for(i=0;i
    65. SwitchBot_Subject.array_observer[i]=0;
    66. SwitchBot_Subject.notify_observer=woan_notify_observer;
    67. SwitchBot_Subject.remove_observer=woan_remove_observer;
    68. SwitchBot_Subject.register_observer=woan_notify_observer;
    69. }
    70. uint8_t get_date(int *buf)
    71. {
    72. //buf get something
    73. }
    74. void check_and_notify()
    75. {
    76. int *buf;
    77. int state=0;
    78. get_date(buf);
    79. if(buf[0] == 0x570f0201)
    80. SwitchBot_Subject.notify_observer(buf);
    81. }
    82. void init_observer(Observer *observer,void (*update)(void))
    83. {
    84. observer->update=update;
    85. }
    86. void add_observer(Subject *subject,Observer *observer)
    87. {
    88. subject->register_observer(observer);
    89. }
    90. void main()
    91. {
    92. interfaces_update_Audio_t *audio_func;
    93. interfaces_update_Video_t *video_func;
    94. init_switchbot_subject();
    95. init_observer(&Audio_Observer,audio_func->update_Audio_date);
    96. init_observer(&Video_Observer,video_func->update_video_date);
    97. init_observer(&Video_Observer,video_func->update_video_date);
    98. add_observer(&SwitchBot_Subject,&Audio_Observer);
    99. add_observer(&SwitchBot_Subject,&Video_Observer);
    100. while(1)
    101. {
    102. check_and_notify();
    103. }
    104. }
    • 观察者适用场景:

    当一个对象状态的改变需要改变其他对象,或实际对象是事
    先未知的或动态变化的时,可使用观察者模式。

    当应用中的一些对象必须观察其他对象时,可使用该模式。
    但仅能在有限时间内或特定情况下使用。
     

    • 优缺点:

    开闭原则。 你无需修改发布者代码就能引入新的订阅者类(如果是发布者接口则可轻松引入发布者类)。
    你可以在运行时建立对象之间的联系。
    订阅者的通知顺序不是随机的
     

  • 相关阅读:
    去外地旅游遇到的问题和心得
    前后端分离开发
    js 关于 replace 取值、替换第几个匹配项
    IDEA使用 Alibaba Cloud Toolkit 插件 自动打包部署maven项目至服务器
    【MetaLearning】有关Pytorch的元学习库higher的基本用法
    Deformable DETR源码解读
    四、npm与包
    VoxWeekly|The Sandbox 生态周报|20230918
    纯电淘汰混动?何小鹏说了不算!
    react跨域如何解决?
  • 原文地址:https://blog.csdn.net/double_lee3/article/details/126764900