模塊化C代碼與UML對象模型之間的映射(2)——抽象類與繼承

 今天繼續寫模塊化C代碼與UML類圖的轉換,所舉例子也許粗糙,主要是演示一下思路,時間允許的話我會盡量按正式的產品開發質量要求來完善代碼示例。

1.4 抽象類與繼承

抽象類是指繼承關係樹中位於樹枝節點的用於被繼承的類,如圖1.5所示。抽象類具有以下特點:

(1)不能被實例化,所以沒有Create或GetInstance方法;

(2)抽象類中方法可以沒有實現體,稱爲抽象方法,它必須被子類重寫。

(3)如果類中包含抽象方法,則必須定義爲抽象類。

順便說一下,圖中void *privateData是類的私有字段,可以利用這個字段擴展功能或簡單忽略之。後面有機會再舉例說明。

 另外,I_DEV是類DEV實現的一組操作集合,公開給用戶,這就是接口,下一節再詳細舉例說明。

UML示例:

圖1.5 抽象類

  

C代碼示例:

 

///////////////////////////////////////////////////////////////////////////////

//inheritance_utils.h

#undef CONTAINING_RECORD
#define CONTAINING_RECORD(address, type, field) \
     ((type *)( (char *)(address) - (unsigned long)(&((type*)0)->field)))

///////////////////////////////////////////////////////////////////////////////
//DEV.h
/* 定義設備操作接口*/
struct I_DEV{
     int (*Add)(struct DEV *, int somePara);
     int (*Delete)(struct DEV *, int somePara);
     int (*Query)(struct DEV *, int somePara);
     int (*Reset)(struct DEV *, int somePara);
};

/* 定義設備類*/
struct DEV{
     void (*Destroy)(struct DEV *);
     void (*Method1)(struct DEV *);
     void (*Method2)(struct DEV *);
     const struct I_DEV *itf;  /* 接口*/
     void *privateData;
};

//抽象類不能實例化,沒有Create
void DEV_Init(struct DEV *DEV, const struct I_DEV *itf); //注意init方法職責是初始化而非實例化
void DEV_Destroy(struct DEV *self);
void DEV_Method1(struct DEV *self);//Method1是具體方法,DEV.c中實現Method1
//Method2是抽象方法,DEV.c中沒有Method2實現體
 
///////////////////////////////////////////////////////////////////////////////
//DEV.c

#include "DEV.h"
void DEV_Init(struct DEV *DEV, const struct I_DEV *itf)
{
     assert(DEV != NULL);
     memset(DEV, 0, sizeof *DEV);
     DEV->itf = itf;
     DEV->Method1 = DEV_Method1;
}

void DEV_Destroy(struct DEV *self)
{
     if (self != NULL)
     {
         free(self);
     }
}

void DEV_Method1(struct DEV *self)
{
     printf("hello, I'm concrete method!\r\n");
}


///////////////////////////////////////////////////////////////////////////////
//WASHER_DEV.h
struct WASHER;  /* 隱藏具體類的細節*/

struct WASHER *WASHER_Create(int type, int id, char *name);
//…

///////////////////////////////////////////////////////////////////////////////
//WASHER.c

#include "DEV.h"
#include “WASHER_DEV.h”
 
/* 定義WASHER設備類*/
struct WASHER
{
     int type;
     int id;
     char *name;
     struct DEV DEV; //繼承DEV類
     void *moreData;
};
 
/* 實現I_DEV接口*/
static int WASHER_Add(struct DEV *DEV, int somePara)
{
     struct WASHER *WASHER;
     WASHER = CONTAINING_RECORD(DEV, struct WASHER, DEV);
     DEV->privateData = WASHER;
     printf("[WASHER_Add]type = %d, id = %d, name = %s\r\n", WASHER->type, WASHER->id, WASHER->name);
     return 0;
}
 
static int WASHER_Query(struct DEV *DEV, int somePara)
{
     struct WASHER *WASHER = (struct WASHER *)DEV->privateData;
     printf("[WASHER_Query]type = %d, id = %d, name = %s\r\n", WASHER->type, WASHER->id, WASHER->name);
     return 0;
}
 
struct I_DEV WASHERItf = {
     WASHER_Add,
     NULL,
     WASHER_Query,
     NULL,
};

/* 派生類實現基類的抽象方法*/
static void WASHER_DEV_Method2(struct DEV *self)
{
     printf("hello, I'm abstract method, implemented by WASHER.\r\n");
}
 
static void WASHER_setup_DEV(struct WASHER *WASHER)
{
     DEV_Init(&WASHER->DEV, &WASHERItf);
     WASHER->DEV.Method2 = WASHER_DEV_Method2;
}
 
static void WASHER_init(struct WASHER *self, int type, int id, char *name)
{
     memset(self, 0, sizeof(struct WASHER));
     self->type = type;
     self->id;
     self->name = name;
     WASHER_setup_DEV(self);
}

struct WASHER *WASHER_Create(int type, int id, char *name)
{
     struct WASHER *WASHER = (struct WASHER *)malloc(sizeof(struct WASHER));
     WASHER_init(WASHER, type, id, name);
     return WASHER;
}
///////////////////////////////////////////////////////////////////////////////
//test_WASHER_DEV.c

#include "WASHER_DEV.h"

TEST(test_DEV_inheritance, test_demo)
{
     int type = 3;
     int id = 1;
     char *name = "WASHER";
     struct WASHER * WASHER = WASHER_Create(type, id, name);
     // Usually register WASHER first. Here’s just a demo…
     //針對接口/抽象編程
     struct DEV *DEV = &(WASHER->DEV);
     EXPECT_EQ(0, DEV->itf->Add(DEV, 0xff));
     EXPECT_EQ(0, DEV->itf->Query(DEV, 0xff));
     DEV->Method1(DEV);
     DEV->Method2(DEV);
}

//e.g. user: bd = add(type, id, "DEVname");  query(bd, para);
又到11點了,該睡覺覺羅~~


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章