【 C语言 】 C语言设计模式

【 C语言 】 C语言设计模式我们知道 在现实的软件开发过程当中 用户的要求是多种多样的

大家好,欢迎来到IT知识分享网。

一 、C语言和设计模式(继承、封装、多态)

  1. typedef struct _parent
  2. {
  3.  int data_parent; 
  4. }Parent;
  5. typedef struct _Child
  6. {
  7.  struct _parent parent; 
  8. int data_child; 
  9. }Child;
    在设计C语言继承性的时候,我们需要做的就是把基础数据放在继承的结构的首位置即可。这样,不管是数据的访问、数据的强转、数据的访问都不会有什么问题。
  1. struct _Data;
  2. typedef void (process)(struct _Data pData);
  3. typedef struct _Data
  4. {
  5.  int value; 
  6.  process pProcess; 
  7. }Data;
    封装性的意义在于,函数和数据是绑在一起的,数据和数据是绑在一起的。这样,我们就可以通过简单的一个结构指针访问到所有的数据,遍历所有的函数。封装性,这是类拥有的属性,当然也是数据结构体拥有的属性。
  1. typedef struct _Play
  2. {
  3.  void* pData; 
  4.  void (*start_play)(struct _Play* pPlay); 
  5. }Play;
    多态,就是说用同一的接口代码处理不同的数据。比如说,这里的Play结构就是一个通用的数据结构,我们也不清楚pData是什么数据,start_play是什么处理函数?但是,我们处理的时候只要调用pPlay->start_play(pPlay)就可以了。剩下来的事情我们不需要管,因为不同的接口会有不同的函数去处理,我们只要学会调用就可以了。
  1. typedef struct _Tofu
  2. {
  3.  int type; 
  4.  void (*eat) (struct _Visitor* pVisitor, struct _Tofu* pTofu); 
  5. }Tofu;
  6. typedef struct _Visitor
  7. {
  8.  int region; 
  9. void (*process)(struct _Tofu* pTofu, struct _Visitor* pVisitor); 
  10. }Visitor;
    就是这样一个豆腐,eat的时候就要做不同的判断了。
    [cpp] view plaincopy

  11. void eat(struct _Visitor* pVisitor, struct _Tofu* pTofu)
  12. {
  13.  assert(NULL != pVisitor && NULL != pTofu); 
  14.  pVisitor->process(pTofu, pVisitor); 
  15. }
    既然eat的操作最后还是靠不同的visitor来处理了,那么下面就该定义process函数了。
    [cpp] view plaincopy

  16. void process(struct _Tofu* pTofu, struct _Visitor* pVisitor)
  17. {
  18.  assert(NULL != pTofu && NULL != pVisitor); 
  19.  if(pTofu->type == SPICY_FOOD && pVisitor->region == WEST || 
  20.  pTofu->type == STRONG_SMELL_FOOD && pVisitor->region == EAST) 
  21.  { 
  22.  printf("I like this food!\n"); 
  23.  return; 
  24. } 
  25. printf("I hate this food!\n"); 
  26. }
  1. typedef struct _State
  2. {
  3.  void (*process)(); 
  4.  struct _State* (*change_state)(); 
  5. }State;
    说明一下,这里定义了两个变量,分别process函数和change_state函数。其中proces函数就是普通的数据操作,
    [cpp] view plaincopy

  6. void normal_process()
  7. {
  8.  printf("normal process!\n"); 
  9. }
    change_state函数本质上就是确定下一个状态是什么。
    [cpp] view plaincopy

  10. struct _State* change_state()
  11. {
  12.  State* pNextState = NULL; 
  13.  pNextState = (struct _State*)malloc(sizeof(struct _State)); 
  14.  assert(NULL != pNextState); 
  15.  pNextState ->process = next_process; 
  16.  pNextState ->change_state = next_change_state; 
  17. return pNextState; 
  18. }
    所以,在context中,应该有一个state变量,还应该有一个state变换函数。
    [cpp] view plaincopy

  19. typedef struct _Context
  20. {
  21.  State* pState; 
  22.  void (*change)(struct _Context* pContext); 
  23. }Context;
  24. void context_change(struct _Context* pContext)
  25. {
  26. State* pPre; 
  27. assert(NULL != pContext); 
  28. pPre = pContext->pState; 
  29. pContext->pState = pPre->changeState(); 
  30. free(pPre); 
  31. return; 
  32. }
首先定义post的相关数据。 

[cpp] view plaincopy

  1. typedef struct _Post
  2. {
  3.  void (*do)(struct _Post* pPost); 
  4. }Post;
    Post完成了实际的投递工作,那么命令呢?
    [cpp] view plaincopy

  5. typedef struct _Command
  6. {
  7.  void* pData; 
  8.  void (*exe)(struct _Command* pCommand); 
  9. }Command;
  10. void post_exe(struct _Command* pCommand)
  11. {
  12. assert(NULL != pCommand); 
  13. (Post*)(pCommand->pData)->do((Post*)(pCommand->pData)); 
  14. return; 
  15. }
    我们看到了Post、Command的操作,那么剩下的就是boss的定义了。
    [cpp] view plaincopy

  16. typedef struct _Boss
  17. {
  18.  Command* pCommand; 
  19.  void (*call)(struct _Boss* pBoss); 
  20. }Boss;
  21. void boss_call(struct _Boss* pBoss)
  22. {
  23.  assert(NULL != pBoss); 
  24. pBoss->pCommand->exe(pBoss->pCommand); 
  25. return; 
  26. }
  1. typedef struct _Interpret
  2. {
  3.  int type; 
  4.  void* (*process)(void* pData, int* type, int* result); 
  5. }Interpret;
    上面的数据结构比较简单,但是很能说明问题。就拿变量来说吧,这里就可以定义成字母的解释器、数字解释器、下划线解释器三种形式。所以,我们可以进一步定义一下process的相关函数。

[cpp] view plaincopy

  1. #define DIGITAL_TYPE 1
  2. #define LETTER_TYPE 2
  3. #define BOTTOM_LINE 3
  4. void* digital_process(void* pData, int* type, int* result)
  5. {
  6.  UINT8* str; 
  7.  assert(NULL != pData && NULL != type && NULL != result); 
  8. str = (UNT8*)pData; 
  9. while (*str >= '0' && *str <= '9') 
  10. { 
  11.  str ++; 
  12. } 
  13. if(*str == '\0') 
  14. { 
  15.  *result = TRUE; 
  16.  return NULL; 
  17. } 
  18. if(*str == '_') 
  19. { 
  20.  *result = TRUE; 
  21.  *type = BOTTOM_TYPE; 
  22.  return str; 
  23. } 
  24. if(*str >= 'a' && *str <= 'z' || *str >= 'A' && *str <= 'Z') 
  25. { 
  26.  *result = TRUE; 
  27.  *type = LETTER_TYPE; 
  28.  return str; 
  29. } 
  30. *result = FALSE; 
  31. return NULL; 
  32. }
  33. void* letter_process(void* pData, int* type, int* result)
  34. {
  35. UINT8* str; 
  36. assert(NULL != pData && NULL != type && NULL != result); 
  37. str = (UNT8*)pData; 
  38. while (*str >= 'a' && *str <= 'z' || *str >= 'A' && *str <= 'Z') 
  39. { 
  40.  str ++; 
  41. } 
  42. if(*str == '\0') 
  43. { 
  44.  *result = TRUE; 
  45.  return NULL; 
  46. } 
  47. if(*str == '_') 
  48. { 
  49.  *result = TRUE; 
  50.  *type = BOTTOM_TYPE; 
  51.  return str; 
  52. } 
  53. if(*str >= '0' && *str <= '9') 
  54. { 
  55.  *result = TRUE; 
  56.  *type = DIGITAL_TYPE; 
  57.  return str; 
  58. } 
  59. *result = FALSE; 
  60. return NULL; 
  61. }
  62. void* bottom_process(void* pData, int* type, int* result)
  63. {
  64. UINT8* str; 
  65. assert(NULL != pData && NULL != type && NULL != result); 
  66. str = (UNT8*)pData; 
  67. while ('_' == *str ) 
  68. { 
  69.  str ++; 
  70. } 
  71. if(*str == '\0') 
  72. { 
  73.  *result = TRUE; 
  74.  return NULL; 
  75. } 
  76. if(*str >= 'a' && *str <= 'z' || *str >= 'A' && *str <= 'Z') 
  77. { 
  78.  *result = TRUE; 
  79.  *type = LETTER_TYPE; 
  80.  return str; 
  81. } 
  82. if(*str >= '0' && *str <= '9') 
  83.  { 
  84.  *result = TRUE; 
  85.  *type = DIGITAL_TYPE; 
  86.  return str; 
  87.  } 
  88.  *result = FALSE; 
  89.  return NULL; 
  90. }
既然是撤销,那么我们在进行某种动作的时候,就应该创建一个相应的撤销操作?这个撤销操作的相关定义可以是这样的。 

[cpp] view plaincopy

  1. typedef struct _Action
  2. {
  3.  int type; 
  4.  struct _Action* next; 
  5.  void* pData; 
  6.  void (*process)(void* pData); 
  7. }Action;
    数据结构中定义了两个部分:撤销的数据、恢复的操作。那么这个撤销函数应该有一个创建的函数,还有一个恢复的函数。所以,作为撤销动作的管理者应该包括,
    [cpp] view plaincopy

  8. typedef struct _Organizer
  9. {
  10.  int number; 
  11.  Action* pActionHead; 
  12.  Action* (*create)(); 
  13.  void (*restore)(struct _Organizer* pOrganizer); 
  14. }Organizer;
    既然数据在创建和修改的过程中都会有相应的恢复操作,那么要是真正恢复原来的数据也就变得非常简单了。
    [cpp] view plaincopy

  15. void restore(struct _Organizer* pOrganizer)
  16. {
  17.  Action* pHead; 
  18.  assert(NULL != pOrganizer); 
  19.  pHead = pOrganizer->pActionHead; 
  20.  pHead->process(pHead->pData); 
  21.  pOrganizer->pActionHead = pHead->next; 
  22.  pOrganizer->number --; 
  23. free(pHead); 
  24. return; 
  25. }
  1. typedef struct _Object
  2. {
  3.  observer* pObserverList[MAX_BINDING_NUMBER]; 
  4.  int number; 
  5.  void (*notify)(struct _Object* pObject); 
  6.  void (*add_observer)(observer* pObserver); 
  7.  void (*del_observer)(observer* pObserver); 
  8. }Object;
    其实,我们需要定义的就是观察者本身了。就像我们前面说的一样,观察者可以是菜单、工具栏或者是子窗口等等。
    [cpp] view plaincopy

  9. typedef struct _Observer
  10. {
  11.  Object* pObject; 
  12.  void (*update)(struct _Observer* pObserver); 
  13. }Observer;
    紧接着,我们要做的就是在Observer创建的时候,把observer自身绑定到Object上面。
    [cpp] view plaincopy

  14. void bind_observer_to_object(Observer* pObserver, Object* pObject)
  15. {
  16.  assert(NULL != pObserver && NULL != pObject); 
  17.  pObserver->pObject = pObject; 
  18.  pObject->add_observer(pObserver); 
  19. }
  20. void unbind_observer_from_object(Observer* pObserver, Object* pObject)
  21. {
  22. assert(NULL != pObserver && NULL != pObject); 
  23. pObject->del_observer(observer* pObserver); 
  24. memset(pObserver, 0, sizeof(Observer)); 
  25. }
    既然Observer在创建的时候就把自己绑定在某一个具体的Object上面,那么Object发生改变的时候,统一更新操作就是一件很容易的事情了。
    [cpp] view plaincopy

  26. void notify(struct _Object* pObject)
  27. {
  28.  Obserer* pObserver; 
  29.  int index; 
  30.  assert(NULL != pObject); 
  31.  for(index = 0; index < pObject->number; index++) 
  32.  { 
  33.  pObserver = pObjecet->pObserverList[index]; 
  34.  pObserver->update(pObserver); 
  35. } 
  36. }
  1. typedef struct _MeatDumpling
  2. {
  3.  void (*make)(); 
  4. }MeatDumpling;
  5. typedef struct _NormalDumpling
  6. {
  7.  void (*make)(); 
  8. }NormalDumpling;
    上面只是对饺子进行归类。第一类是对肉馅饺子的归类,第二类是对素馅饺子的归类,这些地方都没有什么特别之处。那么,关键是我们怎么把它和顾客的要求联系在一起呢?
    [cpp] view plaincopy

  9. typedef struct _DumplingReuqest
  10. {
  11.  int type; 
  12.  void* pDumpling; 
  13. }DumplingRequest;
    这里定义了一个饺子买卖的接口。它的特别支持就在于两个地方,第一是我们定义了饺子的类型type,这个type是可以随便扩充的;第二就是这里的pDumpling是一个void*指针,只有把它和具体的dumpling绑定才会衍生出具体的含义。
    [cpp] view plaincopy

  14. void buy_dumpling(DumplingReuqest* pDumplingRequest)
  15. {
  16.  assert(NULL != pDumplingRequest); 
  17.  if(MEAT_TYPE == pDumplingRequest->type) 
  18.  return (MeatDumpling*)(pDumplingRequest->pDumpling)->make(); 
  19.  else 
  20.  return (NormalDumpling*)(pDumplingRequest->pDumpling)->make(); 
  21. }
  1. typedef struct _AssemblePersonalComputer
  2. {
  3.  void (*assemble_cpu)(); 
  4.  void (*assemble_memory)(); 
  5.  void (*assemble_harddisk)(); 
  6. }AssemblePersonalComputer;
    对于一个希望配置intel cpu,samsung 内存、日立硬盘的朋友。他可以这么设计,
    [cpp] view plaincopy

  7. void assemble_intel_cpu()
  8. {
  9.  printf("intel cpu!\n"); 
  10. }
  11. void assemble_samsung_memory()
  12. {
  13.  printf("samsung memory!\n"); 
  14. }
  15. void assemble_hitachi_harddisk()
  16. {
  17. printf("hitachi harddisk!\n"); 
  18. }
    而对于一个希望配置AMD cpu, kingston内存、西部数据硬盘的朋友。他又该怎么做呢?
    [cpp] view plaincopy

  19. void assemble_amd_cpu()
  20. {
  21.  printf("amd cpu!\n"); 
  22. }
  23. void assemble_kingston_memory()
  24. {
  25.  printf("kingston memory!\n"); 
  26. }
  27. void assmeble_western_digital_harddisk()
  28. {
  29. printf("western digital harddisk!\n"); 
  30. }

十、 C语言和设计模式(中介者模式)

  1. typedef struct _Mediator
  2. {
  3.  People* man; 
  4.  People* woman; 
  5. }Mediator;
    上面的数据结构是给媒婆的,那么当然还有一个数据结构是给男方、女方的。
    [cpp] view plaincopy

  6. typedef struct _People
  7. {
  8.  Mediator* pMediator; 
  9.  void (*request)(struct _People* pPeople); 
  10.  void (*process)(struct _Peoplle* pPeople); 
  11. }People;
    所以,这里我们看到的如果是男方的要求,那么这个要求应该女方去处理啊,怎么处理呢?
    [cpp] view plaincopy

  12. void man_request(struct _People* pPeople)
  13. {
  14.  assert(NULL != pPeople); 
  15.  pPeople->pMediator->woman->process(pPeople->pMediator->woman); 
  16. }
    上面做的是男方向女方提出的要求,所以女方也可以向男方提要求了。毕竟男女平等嘛。
    [cpp] view plaincopy

  17. void woman_request(struct _People* pPeople)
  18. {
  19.  assert(NULL != pPeople); 
  20.  pPeople->pMediator->man->process(pPeople->pMediator->man); 
  21. }
  1. typedef struct _MoviePlay
  2. {
  3.  struct _CommMoviePlay* pCommMoviePlay; 
  4. }MoviePlay;
  5. typedef struct _CommMoviePlay
  6. {
  7.  HANDLE hFile; 
  8. void (*play)(HANDLE hFile); 
  9. }CommMoviePlay;
    这个时候呢,对于用户来说,统一的文件接口就是MoviePlay。接下来的一个工作,就是编写一个统一的访问接口。
    [cpp] view plaincopy

  10. void play_movie_file(struct MoviePlay* pMoviePlay)
  11. {
  12.  CommMoviePlay* pCommMoviePlay; 
  13.  assert(NULL != pMoviePlay); 
  14.  pCommMoviePlay = pMoviePlay->pCommMoviePlay; 
  15.  pCommMoviePlay->play(pCommMoviePlay->hFile); 
  16. }
    最后的工作就是对不同的hFile进行play的实际操作,写简单一点就是,
    [cpp] view plaincopy

  17. void play_avi_file(HANDLE hFile)
  18. {
  19.  printf("play avi file!\n"); 
  20. }
  21. void play_rmvb_file(HANDLE hFile)
  22. {
  23.  printf("play rmvb file!\n"); 
  24. }
  25. void play_mpeg_file(HANDLE hFile)
  26. {
  27. printf("play mpeg file!\n"); 
  28. }
  1. class voltage_12v
  2. {
  3. public:
  4.  voltage_12v() {} 
  5.  virtual ~voltage_12v() {} 
  6.  virtual void request() {} 
  7. };
  8. class v220_to_v12
  9. {
  10. public:
  11. v220_to_v12() {} 
  12. ~v220_to_v12() {} 
  13. void voltage_transform_process() {} 
  14. };
  15. class adapter: public voltage_12v
  16. {
  17. v220_to_v12* pAdaptee; 
  18. public:
  19. adapter() {} 
  20. ~adapter() {} 
  21. void request() 
  22. { 
  23.  pAdaptee->voltage_transform_process(); 
  24. } 
  25. };
    通过上面的代码,我们其实可以这样理解。类voltage_12v表示我们的最终目的就是为了获得一个12v的直流电压。当然获得12v可以有很多的方法,利用适配器转换仅仅是其中的一个方法。adapter表示适配器,它自己不能实现220v到12v的转换工作,所以需要调用类v220_to_v12的转换函数。所以,我们利用adapter获得12v的过程,其实就是调用v220_to_v12函数的过程。
    不过,既然我们的主题是用c语言来编写适配器模式,那么我们就要实现最初的目标。这其实也不难,关键一步就是定义一个Adapter的数据结构。然后把所有的Adapter工作都由Adaptee来做,就是这么简单。不知我说明白了没有?
    [cpp] view plaincopy


  26. typdef struct _Adaptee
  27. {
  28.  void (*real_process)(struct _Adaptee* pAdaptee); 
  29. }Adaptee;
  30. typedef struct _Adapter
  31. {
  32.  void* pAdaptee; 
  33.  void (*transform_process)(struct _Adapter* pAdapter); 
  34. }Adapter;
  1. typedef struct _Object
  2. {
  3.  struct _Object* prev; 
  4.  void (*decorate)(struct _Object* pObject); 
  5. }Object;
    装饰模式最经典的地方就是把pObject这个值放在了数据结构里面。当然,装饰模式的奥妙还不仅仅在这个地方,还有一个地方就是迭代处理。我们可以自己随便写一个decorate函数试试看,
    [cpp] view plaincopy

  6. void decorate(struct _Object* pObeject)
  7. {
  8.  assert(NULL != pObject); 
  9.  if(NULL != pObject->prev) 
  10.  pObject->prev->decorate(pObject->prev); 
  11.  printf("normal decorate!\n"); 
  12. }
    所以,装饰模式的最重要的两个方面就体现在:prev参数和decorate迭代处理。
    十四、 C语言和设计模式(享元模式)
    享元模式看上去有点玄乎,但是其实也没有那么复杂。我们还是用示例说话。比如说,大家在使用电脑的使用应该少不了使用WORD软件。使用WORD呢, 那就少不了设置模板。什么模板呢,比如说标题的模板,正文的模板等等。这些模板呢,又包括很多的内容。哪些方面呢,比如说字体、标号、字距、行距、大小等等。
    [cpp] view plaincopy



  13. typedef struct _Font
  14. {
  15.  int type; 
  16.  int sequence; 
  17.  int gap; 
  18.  int lineDistance; 
  19.  void (*operate)(struct _Font* pFont); 
  20. }Font;
    上面的Font表示了各种Font的模板形式。所以,下面的方法就是定制一个FontFactory的结构。
    [cpp] view plaincopy

  21. typedef struct _FontFactory
  22. {
  23.  Font ppFont; 
  24.  int number; 
  25.  int size; 
  26.  Font* GetFont(struct _FontFactory* pFontFactory, int type, int sequence, int gap, int lineDistance); 
  27. }FontFactory;
    这里的GetFont即使对当前的Font进行判断,如果Font存在,那么返回;否则创建一个新的Font模式。
    [cpp] view plaincopy

  28. Font* GetFont(struct _FontFactory* pFontFactory, int type, int sequence, int gap, int lineDistance)
  29. {
  30.  int index; 
  31.  Font* pFont; 
  32.  Font* ppFont; 
  33.  if(NULL == pFontFactory) 
  34.  return NULL; 
  35. for(index = 0; index < pFontFactory->number; index++) 
  36. { 
  37.  if(type != pFontFactory->ppFont[index]->type) 
  38.  continue; 
  39.  if(sequence != pFontFactory->ppFont[index]->sequence) 
  40.  continue; 
  41.  if(gap != pFontFactory->ppFont[index]->gap) 
  42.  continue; 
  43.  if(lineDistance != pFontFactory->ppFont[index]->lineDistance) 
  44.  continue; 
  45.  return pFontFactory->ppFont[index]; 
  46. } 
  47. pFont = (Font*)malloc(sizeof(Font)); 
  48. assert(NULL != pFont); 
  49. pFont->type = type; 
  50. pFont->sequence = sequence; 
  51. pFont->gap = gap; 
  52. pFont->lineDistance = lineDistance; 
  53. if(pFontFactory-> number < pFontFactory->size) 
  54. { 
  55.  pFontFactory->ppFont[index] = pFont; 
  56.  pFontFactory->number ++; 
  57.  return pFont; 
  58. } 
  59. ppFont = (Font)malloc(sizeof(Font*) * pFontFactory->size * 2); 
  60. assert(NULL != ppFont); 
  61. memmove(ppFont, pFontFacoty->ppFont, pFontFactory->size); 
  62. free(pFontFactory->ppFont); 
  63. pFontFactory->size *= 2; 
  64. pFontFactory->number ++; 
  65. ppFontFactory->ppFont = ppFont; 
  66. return pFont; 
  67. }
  1. typedef struct _PC_Client
  2. {
  3.  void (*request)(); 
  4. }PC_Client;
  5. void ftp_request()
  6. {
  7.  printf("request from ftp!\n"); 
  8. }
  9. void http_request()
  10. {
  11. printf("request from http!\n"); 
  12. }
  13. void smtp_request()
  14. {
  15. printf("request from smtp!\n"); 
  16. }
    这个时候,代理的操作应该怎么写呢?怎么处理来自各个协议的请求呢?
    [cpp] view plaincopy

  17. typedef struct _Proxy
  18. {
  19.  PC_Client* pClient; 
  20. }Proxy;
  21. void process(Proxy* pProxy)
  22. {
  23.  assert(NULL != pProxy); 
  24. pProxy->pClient->request(); 
  25. }
  1. typedef struct _FoodSteet
  2. {
  3.  void (*eat)(); 
  4. }FoodStreet;
  5. void eat()
  6. {
  7.  printf("eat here!\n"); 
  8. }
  9. typedef struct _ShopStreet
  10. {
  11. void (*buy)(); 
  12. }ShopStreet;
  13. void buy()
  14. {
  15. printf("buy here!\n"); 
  16. }
  17. typedef struct _BookStreet
  18. {
  19. void (*read)(); 
  20. }BookStreet;
  21. void read()
  22. {
  23. printf("read here"); 
  24. }
    下面,我们就要在一个plaza里面完成所有的项目,怎么办呢?
    [cpp] view plaincopy

  25. typedef struct _Plaza
  26. {
  27.  FoodStreet* pFoodStreet; 
  28.  ShopStreet* pShopStreet; 
  29.  BookStreet* pBookStreet; 
  30.  void (*play)(struct _Plaza* pPlaza); 
  31. }Plaza;
  32. void play(struct _Plaza* pPlaza)
  33. {
  34. assert(NULL != pPlaza); 
  35. pPlaza->pFoodStreet->eat(); 
  36. pPlaza->pShopStreet->buy(); 
  37. pPlaza->pBookStreet->read(); 
  38. }
  1. typedef struct _Container
  2. {
  3.  int* pData; 
  4.  int size; 
  5.  int length; 
  6.  Interator* (*create_new_interator)(struct _Container* pContainer); 
  7.  int (*get_first)(struct _Container* pContainer); 
  8.  int (*get_last)(struct _Container* pContainer); 
  9. }Container;
    我们看到,容器可以创建迭代器。那什么是迭代器呢?
    [cpp] view plaincopy

  10. typedef struct _Interator
  11. {
  12.  void* pVector; 
  13.  int index; 
  14.  int(* get_first)(struct _Interator* pInterator); 
  15.  int(* get_last)(struct _Interator* pInterator); 
  16. }Interator;
    我们看到,容器有get_first,迭代器也有get_first,这中间有什么区别?
    [cpp] view plaincopy

  17. int vector_get_first(struct _Container* pContainer)
  18. {
  19.  assert(NULL != pContainer); 
  20.  return pContainer->pData[0]; 
  21. }
  22. int vector_get_last(struct _Container* pContainer)
  23. {
  24. assert(NULL != pContainer); 
  25. return pContainer->pData[pContainer->size -1]; 
  26. }
  27. int vector_interator_get_first(struct _Interator* pInterator)
  28. {
  29. Container* pContainer; 
  30. assert(NULL != pInterator && NULL != pInterator->pVector); 
  31. pContainer = (struct _Container*) (pInterator->pVector); 
  32. return pContainer ->get_first(pContainer); 
  33. }
  34. int vector_interator_get_last(struct _Interator* pInterator)
  35. {
  36. Container* pContainer; 
  37. assert(NULL != pInterator && NULL != pInterator->pVector); 
  38. pContainer = (struct _Container*) (pInterator->pVector); 
  39. return pContainer ->get_last(pContainer); 
  40. }
    看到上面的代码之后,我们发现迭代器的操作实际上也是对容器的操作而已。
  1. typedef struct _Apple
  2. {
  3.  void (*print_apple)(); 
  4. }Apple;
  5. typedef struct _Grape
  6. {
  7.  void (*print_grape)(); 
  8. }Grape;
    上面分别对苹果和葡萄进行了抽象,当然它们的具体函数也是不一样的。
    [cpp] view plaincopy

  9. void print_white_apple()
  10. {
  11.  printf("white apple!\n"); 
  12. }
  13. void print_red_apple()
  14. {
  15.  printf("red apple!\n"); 
  16. }
  17. void print_white_grape()
  18. {
  19. printf("white grape!\n"); 
  20. }
  21. void print_red_grape()
  22. {
  23. printf("red grape!\n"); 
  24. }
    完成了水果函数的定义。下面就该定义工厂了,和水果一样,我们也需要对工厂进行抽象处理。
    [cpp] view plaincopy

  25. typedef struct _FruitShop
  26. {
  27.  Apple* (*sell_apple)(); 
  28.  Apple* (*sell_grape)(); 
  29. }FruitShop;
    所以,对于卖白苹果、白葡萄的水果店就该这样设计了,红苹果、红葡萄的水果店亦是如此。
    [cpp] view plaincopy

  30. Apple* sell_white_apple()
  31. {
  32.  Apple* pApple = (Apple*) malloc(sizeof(Apple)); 
  33.  assert(NULL != pApple); 
  34.  pApple->print_apple = print_white_apple; 
  35.  return pApple; 
  36. }
  37. Grape* sell_white_grape()
  38. {
  39. Grape* pGrape = (Grape*) malloc(sizeof(Grape)); 
  40. assert(NULL != pGrape); 
  41. pGrape->print_grape = print_white_grape; 
  42. return pGrape; 
  43. }
    这样,基本的框架就算搭建完成的,以后创建工厂的时候,
    [cpp] view plaincopy

  44. FruitShop* create_fruit_shop(int color)
  45. {
  46.  FruitShop* pFruitShop = (FruitShop*) malloc(sizeof(FruitShop)); 
  47.  assert(NULL != pFruitShop); 
  48.  if(WHITE == color) 
  49.  { 
  50.  pFruitShop->sell_apple = sell_white_apple; 
  51.  pFruitShop->sell_grape = sell_white_grape; 
  52. } 
  53. else 
  54. { 
  55.  pFruitShop->sell_apple = sell_red_apple; 
  56.  pFruitShop->sell_grape = sell_red_grape; 
  57. } 
  58. return pFruitShop; 
  59. }
  1. typedef struct _Leader
  2. {
  3.  struct _Leader* next; 
  4.  int account; 
  5.  int (*request)(strcut _Leader* pLeader, int num); 
  6. }Leader;
    所以这个时候,我们首先需要设置额度和领导。

[cpp] view plaincopy

  1. void set_account(struct _Leader* pLeader, int account)
  2. {
  3.  assert(NULL != pLeader); 
  4.  pLeader->account = account; 
  5.  return; 
  6. }
  7. void set_next_leader(const struct _Leader* pLeader, struct _Leader* next)
  8. {
  9. assert(NULL != pLeader && NULL != next); 
  10. pLeader->next = next; 
  11. return; 
  12. }
    此时,如果有一个员工过来报销费用,那么应该怎么做呢?假设此时的Leader是经理,报销额度是10万元。所以此时,我们可以看看报销的费用是不是小于10万元?少于这个数就OK,反之就得上报自己的领导了。
    [cpp] view plaincopy

  13. int request_for_manager(struct _Leader* pLeader, int num)
  14. {
  15.  assert(NULL != pLeader && 0 != num); 
  16.  if(num < ) 
  17.  return 1; 
  18.  else if(pLeader->next) 
  19.  return pLeader->next->request(pLeader->next, num); 
  20.  else 
  21.  return 0; 
  22. }
  1. typedef struct _Shoe
  2. {
  3.  int type; 
  4.  void (*print_shoe)(struct _Shoe*); 
  5. }Shoe;
    就像上面说的,现在有胶鞋,那也有皮鞋,我们该怎么做呢?
    [cpp] view plaincopy

  6. void print_leather_shoe(struct _Shoe* pShoe)
  7. {
  8.  assert(NULL != pShoe); 
  9.  printf("This is a leather show!\n"); 
  10. }
  11. void print_rubber_shoe(struct _Shoe* pShoe)
  12. {
  13.  assert(NULL != pShoe); 
  14. printf("This is a rubber shoe!\n"); 
  15. }
    所以,对于一个工厂来说,创建什么样的鞋子,就看我们输入的参数是什么?至于结果,那都是一样的。
    [cpp] view plaincopy

  16. #define LEATHER_TYPE 0x01
  17. #define RUBBER_TYPE 0x02
  18. Shoe* manufacture_new_shoe(int type)
  19. {
  20.  assert(LEATHER_TYPE == type || RUBBER_TYPE == type); 
  21.  Shoe* pShoe = (Shoe*)malloc(sizeof(Shoe)); 
  22.  assert(NULL != pShoe); 
  23. memset(pShoe, 0, sizeof(Shoe)); 
  24. if(LEATHER_TYPE == type) 
  25. { 
  26.  pShoe->type == LEATHER_TYPE; 
  27.  pShoe->print_shoe = print_leather_shoe; 
  28. } 
  29. else 
  30. { 
  31.  pShoe->type == RUBBER_TYPE; 
  32.  pShoe->print_shoe = print_rubber_shoe; 
  33. } 
  34. return pShoe; 
  35. }
  1. template
  2. int compare (type a, type b)
  3. {
  4.  return a > b ? 1 : 0; 
  5. }
    模板函数提示我们,只要比较的逻辑是确定的,那么不管是什么数据类型,都会得到一个相应的结果。固然,这个比较的流程比较简单,即使没有采用模板函数也没有关系。但是,要是需要拆分的步骤很多,那么又该怎么办呢?如果相通了这个问题,那么也就明白了什么是template模式。
    比方说,现在我们需要设计一个流程。这个流程有很多小的步骤完成。然而,其中每一个步骤的方法是多种多样的,我们可以很多选择。但是,所有步骤构成的逻辑是唯一的,那么我们该怎么办呢?其实也简单。那就是在基类中除了流程函数外,其他的步骤函数全部设置为virtual函数即可。
    [cpp] view plaincopy


  6. class basic
  7. {
  8. public:
  9.  void basic() {} 
  10.  virtual ~basic() {} 
  11.  virtual void step1() {} 
  12.  virtual void step2() {} 
  13.  void process() 
  14.  { 
  15.  step1(); 
  16.  step2(); 
  17. } 
  18. };
    basic的类说明了基本的流程process是唯一的,所以我们要做的就是对step1和step2进行改写。
    [cpp] view plaincopy

  19. class data_A : public basic
  20. {
  21. public:
  22.  data_A() {} 
  23.  ~data_A() {} 
  24.  void step1() 
  25.  { 
  26.  printf("step 1 in data_A!\n"); 
  27.  } 
  28. void step2() 
  29. { 
  30.  printf("step 2 in data_A!\n"); 
  31. } 
  32. };
    所以,按照我个人的理解,这里的template主要是一种流程上的统一,细节实现上的分离。明白了这个思想,那么用C语言来描述template模式就不是什么难事了。
    [cpp] view plaincopy

  33. typedef struct _Basic
  34. {
  35.  void* pData; 
  36.  void (*step1) (struct _Basic* pBasic); 
  37.  void (*step2) (struct _Basic* pBasic); 
  38.  void (*process) (struct _Basic* pBasic); 
  39. }Basic;
    因为在C++中process函数是直接继承的,C语言下面没有这个机制。所以,对于每一个process来说,process函数都是唯一的,但是我们每一次操作的时候还是要去复制一遍函数指针。而step1和step2是不同的,所以各种方法可以用来灵活修改自己的处理逻辑,没有问题。
    [cpp] view plaincopy

  40. void process(struct _Basic* pBasic)
  41. {
  42.  pBasic->step1(pBasic); 
  43.  pBasic->step2(pBasic); 
  44. }
  1. typedef struct _NODE
  2. {
  3.  void* pData; 
  4.  struct _NODE* left; 
  5.  struct _NODE* right; 
  6. }NODE;
    那什么时候是叶子节点,其实就是left、right为NULL的时候。那么如果它们不是NULL呢,那么很明显此时它们已经是父节点了。那么,我们的这个组合模式是怎么一个情况呢?
    [cpp] view plaincopy

  7. typedef struct _Object
  8. {
  9.  struct _Object ppObject; 
  10.  int number; 
  11.  void (*operate)(struct _Object* pObject); 
  12. }Object;
    就是这么一个简单的数据结构,是怎么实现子节点和父节点的差别呢。比如说,现在我们需要对一个父节点的operate进行操作,此时的operate函数应该怎么操作呢?
    [cpp] view plaincopy

  13. void operate_of_parent(struct _Object* pObject)
  14. {
  15.  int index; 
  16.  assert(NULL != pObject); 
  17.  assert(NULL != pObject->ppObject && 0 != pObject->number); 
  18.  for(index = 0; index < pObject->number; index ++) 
  19.  { 
  20.  pObject->ppObject[index]->operate(pObject->ppObject[index]); 
  21. } 
  22. }
    当然,有了parent的operate,也有child的operate。至于是什么操作,那就看自己是怎么操作的了。

[cpp] view plaincopy

  1. void operate_of_child(struct _Object* pObject)
  2. {
  3.  assert(NULL != pObject); 
  4.  printf("child node!\n"); 
  5. }
    父节点也好,子节点也罢,一切的一切都是最后的应用。其实,用户的调用也非常简单,就这么一个简单的函数。

[cpp] view plaincopy

  1. void process(struct Object* pObject)
  2. {
  3.  assert(NULL != pObject); 
  4.  pObject->operate(pObject); 
  5. }
  1. class data
  2. {
  3. public:
  4.  data () {} 
  5.  virtual ~data() {} 
  6.  virtual class data* copy() = 0; 
  7. };
  8. class data_A : public data
  9. {
  10. public:
  11. data_A() {} 
  12. ~data_A() {} 
  13. class data* copy() 
  14. { 
  15.  return new data_A(); 
  16. } 
  17. };
  18. class data_B : public data
  19. {
  20. public:
  21. data_B() {} 
  22. ~data_B() {} 
  23. class data* copy() 
  24. { 
  25.  return new data_B(); 
  26. } 
  27. };
    那怎么使用呢?其实只要一个通用的调用接口就可以了。
    [cpp] view plaincopy

  28. class data* clone(class data* pData)
  29. {
  30.  return pData->copy(); 
  31. }
    就这么简单的一个技巧,对C来说,当然也不是什么难事。
    [cpp] view plaincopy

  32. typedef struct _DATA
  33. {
  34.  struct _DATA* (*copy) (struct _DATA* pData); 
  35. }DATA;
    假设也有这么一个类型data_A,
    [cpp] view plaincopy

  36. DATA data_A = {data_copy_A};
    既然上面用到了这个函数,所以我们也要定义啊。
    [cpp] view plaincopy

  37. struct _DATA* data_copy_A(struct _DATA* pData)
  38. {
  39.  DATA* pResult = (DATA*)malloc(sizeof(DATA)); 
  40.  assert(NULL != pResult); 
  41.  memmove(pResult, pData, sizeof(DATA)); 
  42.  return pResult; 
  43. };
    使用上呢,当然也不含糊。
    [cpp] view plaincopy

  44. struct _DATA* clone(struct _DATA* pData)
  45. {
  46.  return pData->copy(pData); 
  47. };
  1. #include <string.h>
  2. #include <assert.h>
  3. class object
  4. {
  5. public:
  6.  static class object* pObject; 
  7.  static object* create_new_object() 
  8. { 
  9.  if(NULL != pObject) 
  10.  return pObject; 
  11.  pObject = new object(); 
  12.  assert(NULL != pObject); 
  13.  return pObject; 
  14. } 
  15. private:
  16. object() {} 
  17. ~object() {} 
  18. };
  19. class object* object::pObject = NULL;
    单件模式的技巧就在于类的构造函数是一个私有的函数。但是类的构造函数又是必须创建的?怎么办呢?那就只有动用static函数了。我们看到static里面调用了构造函数,就是这么简单。
    [cpp] view plaincopy

  20. int main(int argc, char* argv[])
  21. {
  22.  object* pGlobal = object::create_new_object(); 
  23.  return 1; 
  24. }
    上面说了C++语言的编写方法,那C语言怎么写?其实也简单。大家也可以试一试。
    [cpp] view plaincopy

  25. typedef struct _DATA
  26. {
  27.  void* pData; 
  28. }DATA;
  29. void* get_data()
  30. {
  31.  static DATA* pData = NULL; 
  32. if(NULL != pData) 
  33.  return pData; 
  34. pData = (DATA*)malloc(sizeof(DATA)); 
  35. assert(NULL != pData); 
  36. return (void*)pData; 
  37. }
其实,就我个人看来,不管什么方法都离不开人。一个人写不出二叉树,你怎么让他写?敏捷吗?你写一行,我写一行。还是迭代?写三行,删掉两行,再写三行。项目的成功是偶然的,但是项目的失败却有很多原因,管理混乱、需求混乱、设计低劣、代码质量差、测试不到位等等。就软件企业而言,没有比优秀的文化和出色的企业人才更重要的了。 从软件设计层面来说,一般来说主要包括三个方面: (1)软件的设计受众,是小孩子、老人、女性,还是专业人士等等; (2)软件的基本设计原则,以人为本、模块分离、层次清晰、简约至上、适用为先、抽象基本业务等等; (3)软件编写模式,比如装饰模式、责任链、单件模式等等。 从某种意义上说,设计思想构成了软件的主题。软件原则是我们在开发中的必须遵循的准绳。软件编写模式是开发过程中的重要经验总结。灵活运用设计模式,一方面利于我们编写高质量的代码,另一方面也方便我们对代码进行维护。毕竟对于广大的软件开发者来说,软件的维护时间要比软件编写的时间要多得多。编写过程中,难免要有新的需求,要和别的模块打交道,要对已有的代码进行复用,那么这时候设计模式就派上了用场。我们讨论的主题其实就是设计模式。 讲到设计模式,人们首先想到的语言就是c#或者是java,最不济也是c++,一般来说没有人会考虑到c语言。其实,我认为设计模式就是一种基本思想,过度美化或者神化其实没有必要。其实阅读过linux kernel的朋友都知道,linux虽然自身支持很多的文件系统,但是linux自身很好地把这些系统的基本操作都抽象出来了,成为了基本的虚拟文件系统。 举个例子来说,现在让你写一个音乐播放器,但是要支持的文件格式很多,什么ogg,wav,mp3啊,统统要支持。这时候,你会怎么编写呢?如果用C++语言,你可能会这么写。 

[cpp] view plaincopy

  1. class music_file
  2. {
  3.  HANDLE hFile; 
  4. public:
  5.  void music_file() {} 
  6.  virtual ~music_file() {} 
  7.  virtual void read_file() {} 
  8.  virtual void play() {} 
  9. virtual void stop() {} 
  10. virtual void back() {} 
  11. virtual void front() {} 
  12. virtual void up() {} 
  13. virtual void down() {} 
  14. };
    其实,你想想看,如果用C语言能够完成相同的抽象操作,那不是效果一样的吗?

[cpp] view plaincopy

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

    希望和大家共勉。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/116899.html

(0)
上一篇 2025-11-25 14:00
下一篇 2025-11-25 14:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信