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

Posted on 2013-11-22 11:40  已过而立  阅读(639)  评论(3编辑  收藏  举报

定义

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

 

要点

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

 

类图 

    网上截取的

  

 

代码实现及实例

  要求: 单片机程序中,检测某一输入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中初始化、注册就行了

 

Copyright © 2024 已过而立
Powered by .NET 8.0 on Kubernetes