C与设计模式---装饰者模式

Posted on 2013-11-23 00:20  已过而立  阅读(552)  评论(0编辑  收藏  举报

定义

  动态地将责任附加到对象上若要扩展功能,装饰者提供了比继承更有弹性的替代方案 

 

要点 

  • 继承属于扩展形式之一,但不见得是达到弹性设计的最佳方案
  • 尽量不修改现有的代码,允许扩展代码
  • 装饰者模式意味着有很多用来包装具体组件的装饰者类
  • 装饰者类可以在被装饰者的行为前面或后面加上自己的行为,甚至替换掉被装饰者的行为来达到自己的目的
  • 可以有无数个装饰者包装一个组件
  • 在客户程序不依赖于组件的具体类型的情况下,装饰者对组件的客户是透明的
  • 装饰者会导致设计中出现许多小的对象,不要过度使用

类图

  还是网上下的

 

白话

  不知道小时候有没有玩过一个游戏,游戏玩法就是几个人在一些小纸条上写上各自的名字,然后再在另外的纸条上分别写上时间、地点、和谁、干什么了,最后把这些纸条混在一起,大家随便抽,最后把各自抽到的纸条组在一起,看凑在一起的是什么话,比如有 "张三10点多在屋顶上打飞机"之类的,大家就笑了。。。。

     将这个游戏代入到装饰者模式中来,很显然,写在纸上的都是 "汉字"(IObject),它们要"组合"(Method)在一起,要对人物组件 "张三"(object1)、"李四"(object2)用别的字进行包装"组合"(Method)。怎么包装呢,"随机抽"(Decorator)了"组合"(Method)在一起,哪些字可以用来抽列,就是剩下的"时间"(A_Decorator),"地点"(B_Decorator),"干什么"(C_Decorator) ,这些都是可以被抽了"组合"(Method)在一起的。最后调用某个人物的"组合"(Method)方法就成了让大家发笑的一句话了。

 

代码实现及实例

 
  装饰者模式实际上是一种迭代处理方式,吐槽一下,能不用迭代,尽量不要用迭代。

  有个酒店楼层房间管理系统,由上位机和各个楼层的信息监测设备节点组成。设备节点通过网络将数据传送给上位机。需传送的数据有很多类型,而且每种类型又包含很多子类型。截取一部分来实现。

       将每次需要传送的数据包统称为一个数据帧。假设有2种数据帧,大的类型分为2个,一是固定长度的帧(Fixed_Frame),二是不固定长度的帧(UnFixed_Frame);小的类型分为4个,确认帧(Confirm_Frame)、参数帧(Param_Frame)、实时数据帧(RTData_Frame)、带时标(TFlag_Frame)

     各个类型的代码实现

  

extern unsigned char frame_buffer[128];

#define START_BYTE 0x68


//抽象组件
typedef struct _iobject
{
    struct _iobject *prev;   
    
    int cr_data_len;  //用于记录数据的默认长度,在初始化obj时赋初值
    int data_len;     //用于记录已有的obj.cr_data_len之和
    int var_data_len;  //接口函数中用来存储长度值的变量
    
    int (*frame_creater)(struct _iobject *obj);  //接口函数
}Iobject;


//具体组件
Iobject Fixed_Frame;              //固定帧
Iobject UnFixed_Frame;            //可变长度帧

//具体装饰者
Iobject Confirm_Frame;            //确认帧
Iobject Param_Frame;            //参数帧
Iobject RTData_Frame;            //实时数据帧
Iobject TFlag_Frame;            //带时标


//抽象的装饰者 
Iobject Decorator;   

抽象的装饰者Decorator可以直接用下面的decorator_frame_creater函数直接代替,为了形象点, 最后还是加上了

相关函数

  

//初始化某个Iobject的变量
//参数说明就略了
void init_iobject(Iobject *obj,int cr_data_len,int (*frame_creater)(Iobject *m_obj))
{
    obj->cr_data_len=cr_data_len;
    obj->data_len=0;
    obj->frame_creater=frame_creater;
    obj->prev=0;
}


//置current的prev值
void add_iobject(Iobject *current,Iobject *prev)
{
    prev->data_len=current->cr_data_len+current->data_len;
    current->prev=prev;
}

//接口函数
int decorator_frame_creater(struct _iobject *obj)
{
    obj->var_data_len=0;
    if(obj->prev!=0)
        obj->var_data_len=obj->prev->frame_creater(obj->prev);
    return obj->var_data_len;
}

//固定帧的装饰,加了1个开头标识
int  Fixed_frame_creater(struct _iobject *obj)
{
    obj->var_data_len=decorator_frame_creater(obj);
    frame_buffer[obj->data_len]=START_BYTE;
    return obj->cr_data_len+obj->var_data_len;
}

//确认帧的装饰,加了2个0
int  Confirm_Frame_frame_creater(struct _iobject *obj)
{
    obj->var_data_len=decorator_frame_creater(obj);
    frame_buffer[obj->data_len]=0x00;
    frame_buffer[obj->data_len+1]=0x00;
    return obj->cr_data_len+obj->var_data_len;
}

最后是使用

int main(void)
{
    
    int count=0;
    
    init_iobject(&Fixed_Frame,1,Fixed_frame_creater);
    init_iobject(&Confirm_Frame,2,Confirm_Frame_frame_creater);
    init_iobject(&Decorator,0,decorator_frame_creater);
    
    while(1)
    {
        
        //置发送帧的一些配置选项,假设需要发送一个确认的固定帧
        add_iobject(&Decorator,&Fixed_Frame);
        add_iobject(&Fixed_Frame,&Confirm_Frame);
        
        //调用decorator的接口函数
        count=Decorator.frame_creater(&Decorator);
        
        //网卡发送数据帧
        eth_send(frame_buffer,count);
    }
}

可以看到,在维护修改程序时,如果要添加新的帧,就要添加一些的新的iobject结构,少了还好,多了后就很繁琐了,要是内存还很小的话,还耗费内存。另外装饰者模式采用迭代方式,虽然杜绝了死循环的可能,但是在迭代函数的实现中,若是局部变量过多了,也浪费了栈的空间,甚至可能导致栈溢出,个人认为,嵌入式中,少用为好

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