打印
[C语言]

C语言和设计模式==连载

[复制链接]
7293|38
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lhchen922|  楼主 | 2013-11-5 21:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 lhchen922 于 2013-11-5 21:27 编辑

最近学习OOPC,软件编程模式,看到下面一篇好的**,特与二姨网友分享。
申明:此文为转载,用意是让大家一起学习,一起进步。

go..............................

一.C语言和设计模式之开篇
【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

    关于软件设计方面的书很多,比如《重构》,比如《设计模式》。至于软件开发方式,那就更多了,什么极限编程、精益方法、敏捷方法。随着时间的推移,很多的方法又会被重新提出来。

    其实,就我个人看来,不管什么方法都离不开人。一个人写不出二叉树,你怎么让他写?敏捷吗?你写一行,我写一行。还是迭代?写三行,删掉两行,再写三行。项目的成功是偶然的,但是项目的失败却有很多原因,管理混乱、需求混乱、设计低劣、代码质量差、测试不到位等等。就软件企业而言,没有比优秀的文化和出色的企业人才更重要的了。

    从软件设计层面来说,一般来说主要包括三个方面:
    (1)软件的设计受众,是小孩子、老人、女性,还是专业人士等等;
    (2)软件的基本设计原则,以人为本、模块分离、层次清晰、简约至上、适用为先、抽象基本业务等等;
    (3)软件编写模式,比如装饰模式、责任链、单件模式等等。

    从某种意义上说,设计思想构成了软件的主题。软件原则是我们在开发中的必须遵循的准绳。软件编写模式是开发过程中的重要经验总结。灵活运用设计模式,一方面利于我们编写高质量的代码,另一方面也方便我们对代码进行维护。毕竟对于广大的软件开发者来说,软件的维护时间要比软件编写的时间要多得多。编写过程中,难免要有新的需求,要和别的模块打交道,要对已有的代码进行复用,那么这时候设计模式就派上了用场。我们讨论的主题其实就是设计模式。

    讲到设计模式,人们首先想到的语言就是c#或者是java,最不济也是c++,一般来说没有人会考虑到c语言。其实,我认为设计模式就是一种基本思想,过度美化或者神化其实没有必要。其实阅读过linux kernel的朋友都知道,linux虽然自身支持很多的文件系统,但是linux自身很好地把这些系统的基本操作都抽象出来了,成为了基本的虚拟文件系统。
   
    举个例子来说,现在让你写一个音乐播放器,但是要支持的文件格式很多,什么ogg,wav,mp3啊,统统要支持。这时候,你会怎么编写呢?如果用C++语言,你可能会这么写。
class music_file  
{  
    HANDLE hFile;  
  
public:  
    void music_file() {}  
    virtual ~music_file() {}  
    virtual void read_file() {}  
    virtual void play() {}  
    virtual void stop() {}  
    virtual void back() {}  
    virtual void front() {}  
    virtual void up() {}  
    virtual void down() {}      
};

    其实,你想想看,如果用C语言能够完成相同的抽象操作,那不是效果一样的吗?
typedef struct _music_file  
{  
    HANDLE hFile;  
    void (*read_file)(struct _music_file* pMusicFile);  
    void (*play)(struct _music_file* pMusicFile);  
    void (*stop)(struct _music_file* pMusicFile);  
    void (*back)(struct _music_file* pMusicFile);  
    void (*front)(struct _music_file* pMusicFile);  
    void (*down)(struct _music_file* pMusicFile);  
    void (*up)(struct _music_file* pMusicFile);            
}music_file;  


    当然,上面的例子比较简单,但是也能说明一些问题。写这篇**的目的一是希望和朋友们共同学习模式的相关内容,另一方面也希望朋友们能够活学活用,既不要迷信权威,也不要妄自菲薄。只要付出努力,付出汗水,肯定会有收获的。有些大环境你改变不了,那就从改变自己开始。万丈高楼平地起,一步一个脚印才能真真实实学到东西。如果盲目崇拜,言必google、微软、apple,那么除了带来几个唾沫星,还能有什么受用呢?无非白费了口舌而已。

    希望和大家共勉。


相关帖子

沙发
lhchen922|  楼主 | 2013-11-5 21:05 | 只看该作者
本帖最后由 lhchen922 于 2013-11-11 22:54 编辑

二。C语言和设计模式(之单件模式)
【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

PS:所谓单件模式即保证一个类仅有一个实例,并提供一个访问它的全局访问点。

    有过面试经验的朋友,或者对设计模式有点熟悉的朋友,都会对单件模式不陌生。对很多面试官而言,单件模式更是他们面试的保留项目。其实,我倒认为,单件模式算不上什么设计模式。最多也就是个技巧。

    单件模式要是用C++写,一般这么写。


#include <string.h>  
#include <assert.h>  
  
class object  
{  
public:  
    static class object* pObject;  
      
    static object* create_new_object()  
    {  
        if(NULL != pObject)  
            return pObject;  
  
        pObject = new object();  
        assert(NULL != pObject);  
        return pObject;  
    }  
      
private:  
    object() {}  
    ~object() {}  
};  
  
class object* object::pObject = NULL;  

    单件模式的技巧就在于类的构造函数是一个私有的函数。但是类的构造函数又是必须创建的?怎么办呢?那就只有动用static函数了。我们看到static里面调用了构造函数,就是这么简单。

int main(int argc, char* argv[])  
{  
    object* pGlobal = object::create_new_object();  
    return 1;  
}  

    上面说了C++语言的编写方法,那C语言怎么写?其实也简单。大家也可以试一试。

typedef struct _DATA  
{  
    void* pData;  
}DATA;  
  
void* get_data()  
{  
    static DATA* pData = NULL;  
      
    if(NULL != pData)  
        return pData;  
  
    pData = (DATA*)malloc(sizeof(DATA));  
    assert(NULL != pData);  
    return (void*)pData;  
}  


使用特权

评论回复
板凳
lhchen922|  楼主 | 2013-11-5 21:07 | 只看该作者
本帖最后由 lhchen922 于 2013-11-5 21:30 编辑

三.C语言和设计模式(之原型模式)

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

    原型模式本质上说就是对当前数据进行复制。就像变戏法一样,一个鸽子变成了两个鸽子,两个鸽子变成了三个鸽子,就这么一直变下去。在变的过程中,我们不需要考虑具体的数据类型。为什么呢?因为不同的数据有自己的复制类型,而且每个复制函数都是虚函数。

    用C++怎么编写呢,那就是先写一个基类,再编写一个子类。就是这么简单。


class data  
{  
public:  
    data () {}  
    virtual ~data() {}  
    virtual class data* copy() = 0;  
};  
  
class data_A : public data  
{  
public:  
    data_A() {}  
    ~data_A() {}  
    class data* copy()  
    {  
        return new data_A();  
    }  
};  
  
class data_B : public data  
{  
public:  
    data_B() {}  
    ~data_B() {}  
    class data* copy()  
    {  
        return new data_B();  
    }   
};  


    那怎么使用呢?其实只要一个通用的调用接口就可以了。
class data* clone(class data* pData)  
{  
    return pData->copy();  
}



    就这么简单的一个技巧,对C来说,当然也不是什么难事。

typedef struct _DATA  
{  
    struct _DATA* (*copy) (struct _DATA* pData);  
}DATA;  


    假设也有这么一个类型data_A,

DATA data_A = {data_copy_A};  


    既然上面用到了这个函数,所以我们也要定义啊。

struct _DATA* data_copy_A(struct _DATA* pData)  
{  
    DATA* pResult = (DATA*)malloc(sizeof(DATA));  
    assert(NULL != pResult);  
    memmove(pResult, pData, sizeof(DATA));  
    return pResult;  
};  


    使用上呢,当然也不含糊。

struct _DATA* clone(struct _DATA* pData)  
{  
    return pData->copy(pData);  
};  


使用特权

评论回复
地板
lhchen922|  楼主 | 2013-11-5 21:24 | 只看该作者
本帖最后由 lhchen922 于 2013-11-5 21:31 编辑

四。C语言和设计模式(之组合模式)
【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

    组合模式听说去很玄乎,其实也并不复杂。为什么?大家可以先想一下数据结构里面的二叉树是怎么回事。为什么就是这么一个简单的二叉树节点既可能是叶节点,也可能是父节点?


typedef struct _NODE  
{  
    void* pData;  
    struct _NODE* left;  
    struct _NODE* right;  
}NODE;  


    那什么时候是叶子节点,其实就是left、right为NULL的时候。那么如果它们不是NULL呢,那么很明显此时它们已经是父节点了。那么,我们的这个组合模式是怎么一个情况呢?
typedef struct _Object  
{  
    struct _Object** ppObject;  
    int number;  
    void (*operate)(struct _Object* pObject);  
  
}Object;  


    就是这么一个简单的数据结构,是怎么实现子节点和父节点的差别呢。比如说,现在我们需要对一个父节点的operate进行操作,此时的operate函数应该怎么操作呢?
void operate_of_parent(struct _Object* pObject)  
{  
    int index;  
    assert(NULL != pObject);  
    assert(NULL != pObject->ppObject && 0 != pObject->number);  
  
    for(index = 0; index < pObject->number; index ++)  
    {  
        pObject->ppObject[index]->operate(pObject->ppObject[index]);  
    }  
}   

  

    当然,有了parent的operate,也有child的operate。至于是什么操作,那就看自己是怎么操作的了。

void operate_of_child(struct _Object* pObject)  
{  
    assert(NULL != pObject);  
    printf("child node!\n");  
}  


    父节点也好,子节点也罢,一切的一切都是最后的应用。其实,用户的调用也非常简单,就这么一个简单的函数。

void process(struct Object* pObject)  
{  
    assert(NULL != pObject);  
    pObject->operate(pObject);  
}  


使用特权

评论回复
5
lhchen922|  楼主 | 2013-11-5 21:33 | 只看该作者
五.C语言和设计模式(之模板模式)
【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

    模板对于学习C++的同学,其实并不陌生。函数有模板函数,类也有模板类。那么这个模板模式是个什么情况?我们可以思考一下,模板的本质是什么。比如说,现在我们需要编写一个简单的比较模板函数。


[cpp] view plaincopy


  • template <typename type>  
  • int compare (type a, type b)  
  • {  
  •     return a > b ? 1 : 0;  
  • }      

    模板函数提示我们,只要比较的逻辑是确定的,那么不管是什么数据类型,都会得到一个相应的结果。固然,这个比较的流程比较简单,即使没有采用模板函数也没有关系。但是,要是需要拆分的步骤很多,那么又该怎么办呢?如果相通了这个问题,那么也就明白了什么是template模式。

    比方说,现在我们需要设计一个流程。这个流程有很多小的步骤完成。然而,其中每一个步骤的方法是多种多样的,我们可以很多选择。但是,所有步骤构成的逻辑是唯一的,那么我们该怎么办呢?其实也简单。那就是在基类中除了流程函数外,其他的步骤函数全部设置为virtual函数即可。


[cpp] view plaincopy


  • class basic  
  • {  
  • public:  
  •     void basic() {}  
  •     virtual ~basic() {}  
  •     virtual void step1() {}  
  •     virtual void step2() {}  
  •     void process()  
  •     {  
  •         step1();  
  •         step2();  
  •     }  
  • };  

    basic的类说明了基本的流程process是唯一的,所以我们要做的就是对step1和step2进行改写。

[cpp] view plaincopy


  • class data_A : public basic  
  • {  
  • public:  
  •     data_A() {}  
  •     ~data_A() {}  
  •     void step1()   
  •     {  
  •         printf("step 1 in data_A!\n");  
  •     }  
  •   
  •     void step2()  
  •     {  
  •         printf("step 2 in data_A!\n");  
  •     }  
  • };  

    所以,按照我个人的理解,这里的template主要是一种流程上的统一,细节实现上的分离。明白了这个思想,那么用C语言来描述template模式就不是什么难事了。
[cpp] view plaincopy


  • typedef struct _Basic  
  • {  
  •     void* pData;  
  •     void (*step1) (struct _Basic* pBasic);  
  •     void (*step2) (struct _Basic* pBasic);  
  •     void (*process) (struct _Basic* pBasic);  
  • }Basic;  

    因为在C++中process函数是直接继承的,C语言下面没有这个机制。所以,对于每一个process来说,process函数都是唯一的,但是我们每一次操作的时候还是要去复制一遍函数指针。而step1和step2是不同的,所以各种方法可以用来灵活修改自己的处理逻辑,没有问题。

[cpp] view plaincopy


  • void process(struct _Basic* pBasic)  
  • {  
  •     pBasic->step1(pBasic);  
  •     pBasic->step2(pBasic);  
  • }  




使用特权

评论回复
评论
dong_abc 2013-11-7 00:21 回复TA
改写虚函数达到重构。 
6
lhchen922|  楼主 | 2013-11-5 21:33 | 只看该作者
明天继续吧。。

使用特权

评论回复
7
dong_abc| | 2013-11-5 22:46 | 只看该作者
非常好。

使用特权

评论回复
8
zzyyzz| | 2013-11-6 09:51 | 只看该作者
不错,不错!

使用特权

评论回复
9
chenbb8| | 2013-11-6 11:28 | 只看该作者
这个帖子只是随意的过了一遍,没有深入到应用,特别是嵌入式应该如何应用。
嵌入式设计模式,推荐看<嵌入式系统设计与实践>,虽然才刚开始看,并且试用期工作很忙只有睡觉前能看下,但是这本书很有吸引力~
单例模式(只有单个实例,也就是LS**里的单件模式),书中的说法是比较适合用来访问共享的资源,因为只有一个实例,所以天生带有
防止冲突的特性。
我的应用中一般每个状态机都是只有单个对象(是不是就叫单例呢……只遇到过一个情况下是需要有N个实例的),按照miro samek的命名方法的话
就是AO_XXXX对象(Active object),后来我嫌面向对象的做法太消耗ROM,干脆越过参数传递对象指针的步奏,在函数里直接调用AO_XXXX的元素,
结果被网友批的好惨~
(主要是我在别人讨论面向对象的时候,我给别人示范的例子就这样直接越过传导this指针的步奏,直接操作AO_XXXX,哈哈,连this指针都没有了
不算面向对象了

使用特权

评论回复
10
GZZXB| | 2013-11-6 15:00 | 只看该作者
不错 继续啊

使用特权

评论回复
11
gyh974| | 2013-11-6 20:27 | 只看该作者

使用特权

评论回复
12
lhchen922|  楼主 | 2013-11-6 22:41 | 只看该作者
五。C语言和设计模式(工厂模式)
【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

    工厂模式是比较简单,也是比较好用的一种方式。根本上说,工厂模式的目的就根据不同的要求输出不同的产品。比如说吧,有一个生产鞋子的工厂,它能生产皮鞋,也能生产胶鞋。如果用代码设计,应该怎么做呢?


[cpp] view plaincopy


  • typedef struct _Shoe  
  • {  
  •     int type;  
  •     void (*print_shoe)(struct _Shoe*);  
  • }Shoe;  

    就像上面说的,现在有胶鞋,那也有皮鞋,我们该怎么做呢?

[cpp] view plaincopy


  • void print_leather_shoe(struct _Shoe* pShoe)  
  • {  
  •     assert(NULL != pShoe);  
  •     printf("This is a leather show!\n");  
  • }  
  •   
  • void print_rubber_shoe(struct _Shoe* pShoe)  
  • {  
  •     assert(NULL != pShoe);  
  •     printf("This is a rubber shoe!\n");  
  • }  

    所以,对于一个工厂来说,创建什么样的鞋子,就看我们输入的参数是什么?至于结果,那都是一样的。

[cpp] view plaincopy


  • #define LEATHER_TYPE 0x01  
  • #define RUBBER_TYPE  0x02  
  •   
  • Shoe* manufacture_new_shoe(int type)  
  • {  
  •     assert(LEATHER_TYPE == type || RUBBER_TYPE == type);  
  •   
  •     Shoe* pShoe = (Shoe*)malloc(sizeof(Shoe));  
  •     assert(NULL != pShoe);  
  •   
  •     memset(pShoe, 0, sizeof(Shoe));  
  •     if(LEATHER_TYPE == type)  
  •     {  
  •         pShoe->type == LEATHER_TYPE;  
  •         pShoe->print_shoe = print_leather_shoe;  
  •     }  
  •     else  
  •     {  
  •         pShoe->type == RUBBER_TYPE;  
  •         pShoe->print_shoe = print_rubber_shoe;  
  •     }  
  •   
  •     return pShoe;  
  • }  


使用特权

评论回复
13
lhchen922|  楼主 | 2013-11-6 22:42 | 只看该作者
六.C语言和设计模式(责任链模式)

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】


    责任链模式是很实用的一种实际方法。举个例子来说,我们平常在公司里面难免不了报销流程。但是,我们知道公司里面每一级的领导的报批额度是不一样的。比如说,科长的额度是1000元,部长是10000元,总经理是10万元。

    那么这个时候,我们应该怎么设计呢?其实可以这么理解。比如说,有人来找领导报销费用了,那么领导可以自己先看看自己能不能报。如果费用可以顺利报下来当然最好,可是万一报不下来呢?那就只能请示领导的领导了。


[cpp] view plaincopy


  • typedef struct _Leader  
  • {  
  •     struct _Leader* next;  
  •     int account;  
  •       
  •     int (*request)(strcut _Leader* pLeader, int num);   
  • }Leader;  

    所以这个时候,我们首先需要设置额度和领导。


[cpp] view plaincopy


  • void set_account(struct _Leader* pLeader, int account)  
  • {  
  •     assert(NULL != pLeader);  
  •       
  •     pLeader->account = account;  
  •     return;  
  • }   
  •   
  • void set_next_leader(const struct _Leader* pLeader, struct _Leader* next)  
  • {  
  •     assert(NULL != pLeader && NULL != next);  
  •   
  •     pLeader->next = next;  
  •     return;  
  • }  

    此时,如果有一个员工过来报销费用,那么应该怎么做呢?假设此时的Leader是经理,报销额度是10万元。所以此时,我们可以看看报销的费用是不是小于10万元?少于这个数就OK,反之就得上报自己的领导了。

[cpp] view plaincopy


  • int request_for_manager(struct _Leader* pLeader, int num)  
  • {  
  •     assert(NULL != pLeader && 0 != num);  
  •   
  •     if(num < 100000)  
  •         return 1;  
  •     else if(pLeader->next)   
  •         return pLeader->next->request(pLeader->next, num);     
  •     else   
  •         return 0;  
  • }  


使用特权

评论回复
14
kh31276| | 2013-11-6 23:16 | 只看该作者
不错

使用特权

评论回复
15
gzwfj| | 2013-11-7 13:56 | 只看该作者
求出处???

使用特权

评论回复
16
一个初学者| | 2013-11-7 15:58 | 只看该作者
谢谢分享!~

使用特权

评论回复
17
tang221986| | 2013-11-7 21:11 | 只看该作者
good学习了

使用特权

评论回复
18
zhangfei1987| | 2013-11-7 21:24 | 只看该作者
学习了。

使用特权

评论回复
19
m564522634| | 2013-11-8 09:54 | 只看该作者
哈哈,大神能推荐几版好书吗

使用特权

评论回复
20
hkl_fs| | 2013-11-8 11:17 | 只看该作者
有木有打包的供下载学学?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:<a href="=http://ip.WoTuLa.com" target="_blank"><img src="http://id.WoTuLa.com/1/?name=心有所向&style=2&font=6" /></a>

18

主题

405

帖子

0

粉丝