• C与设计模式---观察者模式


    定义

      定义了主题对象与观察者对象之间的一对多依赖,当主题改变状态时,观察者对象都会收到通知并且自动更新

    要点

    • 观察者模式中的对象之间是一对多的关系
    • 主题使用一个共同的接口来更新观察者
    • 主题与观察者之间采用松耦合的方式结合,主题不知道观察者的细节,只知道观察者实现了某个接口
    • 使用此模式时,观察者可被动等待主题的数据(更好),也可主动获取自己需要的主题的数据

    类图 

        网上截取的

      

    代码实现及实例

      要求: 单片机程序中,检测某一输入IO口的状态,当输入为1时,向UART1、UART2发送数据,并更新液晶显示

      代码实现:

          假设

            IO的状态为 IO_STATE

            设备定义为封装好open,close,send等等操作的Device ,UART1、UART2、LCD为设备名称

    抽象的观察者C代码实现:

    typedef struct observer
    {
        void (*update)();  
    }Observer;

    抽象的主题C代码实现:

    #define OBSERVER_MAX_COUNT        5
    
    typedef struct subject
    {
        Observer *array_observer[OBSERVER_MAX_COUNT];   //每个主题最多支持5个观察者
        
        int (*register_observer)(Observer *observer);  //向主题注册观察者
        int (*remove_observer)(Observer *observer);       //移除观察者
        void (*notify_observer)(void);                //通知消息
        
        //void (*other_function)(void);                //主要指观察者用来主动获取数据的函数
    }Subject;

     创建IO口的Subject。创建UART1、UART2、LCD的Observer,并向subject注册

    Subject IO_Subject;
    
    static int observer_count=0; //记录观察者数量
    
    int f_register_observer(Observer *observer)
    {   
        if(observer_count>=OBSERVER_MAX_COUNT)
            return 0;
        
        IO_Subject.array_observer[observer_count++]=observer;
        
        return 1;
        
    }
    
    int f_remove_observer(Observer *observer)
    {
        int i=0;
        for(i=0;i<observer_count;i++)
        {
            if(observer==IO_Subject.array_observer[i])
            {
                IO_Subject.array_observer[i]=0;
                break;
            }
        }
        
        return 1;
        
    }
    
    
    void f_notify_observer()
    {
        int i=0;
        Observer *observer=0;
        for(i=0;i<observer_count;i++)
        {
            observer=IO_Subject.array_observer[i];
            if(observer!=0)
                observer->update();
        }
        
    }
    
    
    void init_io_subject()
    {
        int i=0;
        
        for(i=0;i<OBSERVER_MAX_COUNT;i++)
            IO_Subject.array_observer[i]=0;
        
        IO_Subject.notify_observer=f_notify_observer;
        IO_Subject.remove_observer=f_remove_observer;
        IO_Subject.register_observer=f_notify_observer;
        
    }
    
    void check_and_notify()
    {
        int state=0;
        
        state=(IO_STATE?1:0);
        
        if(state==1)
            IO_Subject.notify_observer(); 
    }
     
    Observer Uart1_Observer;
    Observer Uart2_Observer;
    Observer Lcd_Observer;
    
    
    void init_observer(Observer *observer,void (*update)(void))
    {
    observer->update=update;
    }

    main中初始化及调用

    void add_observer(Subject *subject,Observer *observer)
    {
        subject->register_observer(observer);
    }
    
    void main()
    {
        init_io_subject();
        
        init_observer(&Uart1_Observer,UART1.send);
        init_observer(&Uart2_Observer,UART2.send);
        init_observer(&Lcd_Observer,    Lcd.send);
        
        add_observer(&IO_Subject,&Uart1_Observer);
        add_observer(&IO_Subject,&Uart2_Observer);
        add_observer(&IO_Subject,&Lcd_Observer);
        
        while(1)
        {
            check_and_notify();
        }
    }

        可以看到,改变主题或者观察者其中任意一方,并不会影响另一方。当我们需要添加另一IO口时,或者动作方式改为收到某个串口数据后再更新LCD时,或者增减一个观察设备时,只需简单的实现对应的结构,在main中初始化、注册就行了

  • 相关阅读:
    最新版-Python和Java实现Aes相互加解密
    tasker 实现短信监听和转发 解决短信验证码登录问题
    某宁 价格爬取 python
    python 获取 某东商品评论数
    xpath 使用
    frida hook 重载函数的几种写法
    Python 爬虫遇到形如 &#x5c0f;&#x8bf4; 的编码如何转换为中文?
    python 使用 pymysql 存,改dic类型数据
    Excel甘特图制作
    关于sunlike ERP的问题解决集
  • 原文地址:https://www.cnblogs.com/yuaren/p/3437237.html
Copyright © 2020-2023  润新知