背景信息
日子一天天过去,业余时间不多,为了避免生活华而不实,碌碌无为,我计划抽空把工作和学习中散落在笔记本和书本某些角落的总结整理出来,放到博客上备忘,同时也希望有机会和技术圈的朋友交流,增长自己的见识,我的qq:18005491。
主题:《面向对象的模块化C编程》
计划提纲:
《模块化C代码与UML类图、时序图、状态图的映射》
《理解模块化》
《UML图示辅助C程序设计是否必要》
《用C练习设计模式》
《PP、TDD的利与弊》
1、有关Modular C的基本知识。建议参考Rober Strandh 的《Modular C ——How to Write Reusable and Maintainable Code using the C Language》,网上还有不少文献。
2、有关UML的基本知识。请参考UML相关书籍,例如Joseph Schmuller的《UML基础、案例与应用(第三版)》。
3、有关面向对象程序设计的基本知识。网上唾手可得。
4、有关模块与类在概念的差异本文不讨论,暂且视为等同的。
关键字:C语言;模块化;UML;面向对象;Modular C;OOPC;OOC
1、类
1、UML示例
图1是一个简单的类图。
MODULE是类的名称;
Create和Destroy分别用于创建和销毁对象;
Serve和ImplementService都是类的方法。
“+”和“-”号用于修饰方法是public还是private的;
Client_TEST是模块的用户。
图1
2、C代码示例
///
//module.h
#ifndef __MODULE__
#define __MODULE__
struct _MODULE;
typedef struct _MODULE MODULE;
#ifdef __cplusplus
extern "C" {
#endif
MODULE *MODULE_Create(void);
void MODULE_Destroy(MODULE *self);
int MODULE_Serve(MODULE *self);
#ifdef __cplusplus
}
#endif
#endif /* __MODULE__ */
///
//module.c
#include "module.h"
struct _MODULE
{
int privateData;
};
static int module_ImplementService(MODULE *self)
{
return ++self->privateData;
}
MODULE *MODULE_Create(int data)
{
MODULE *module = (MODULE *)malloc(sizeof(MODULE));
module->privateData = data;
return module;
}
void MODULE_Destroy(MODULE *self)
{
if (self != NULL)
{
free(self);
}
}
int MODULE_Serve(MODULE *self)
{
return (self != NULL) ? module_ImplementService(self) : 0;
}
///
//test_module.c
#include "module.h" //客户要使用MODULE这个模块
TEST(test_module, case_serve_ok)
{
MODULE *module = MODULE_Create(1); //把MODULE类实例化,即创建对象
EXPECT_EQ(2, MODULE_Serve(module)); //使用MODULE提供的服务
MODULE_Destroy(module); //销毁对象
}
说明:
1、TEST是模块的客户(Client)之一。建议让测试作为新增模块的第一个客户。
2、本例中MODULE类理论上可以被实例化任意多次(当然实际上会受到内存的限制),然而某些应用可能要求某个类只能实例化一次,另外还有一种类型的类叫实用类,请看接下来的介绍。
2、单例类
单例类顾名思义就是类只能有一个实例。说到单例,有个设计模式不得不提,那就是单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点。
关于单例的实际例子就在我们身边,例如,单例就像谈恋爱要专一一样,在我们心里有一个女朋友类,它应该只能有一个实例^_^。再举个靠谱点的例子,请试一下多次运行Windows任务管理器,在界面上是不是只有一个窗口?我猜这就是单例模式的应用。
单例类可进一步分为饿汉式和懒汉式两种,这里暂不展开介绍。
1、UML示例
如图2为单例类。
2、C代码示例
说明:
图2-1和图2-2皆为单例类,二者的区别在于是否运行时动态分配内存。图2-1的私有方法Create表示以动态malloc方式创建对象,需要Destroy方法;图2-2则采用静态分配的方式,无需Destroy。
对应图2-1代码如下:
///
//singleton.h
struct _SINGLETON;
typedef struct _SINGLETON SINGLETON;
SINGLETON *SINGLETON_GetInstance(void);
void SINGLETON_Destroy(SINGLETON *self);
int SINGLETON_Serve(SINGLETON *self);
///
// singleton.c
#include "singleton.h"
struct _SINGLETON
{
char privateData[0];
};
static SINGLETON *gInstance = NULL;
static SINGLETON *singleton_Create(void)
{
SINGLETON *singleton = (SINGLETON *)malloc(sizeof(SINGLETON));
assert(singleton != NULL);
return singleton;
}
SINGLETON *SINGLETON_GetInstance(void)
{
if (NULL == gInstance)
{
gInstance = singleton_Create();
}
return gInstance;
}
void SINGLETON_Destroy(SINGLETON *self)
{
if ((self != NULL) && (self == gInstance))
{
free(gInstance);
gInstance = NULL;
}
}
///
//test_singleton.c
TEST(test_singleton, case_only_one_instance)
{
SINGLETON *instance1 = SINGLETON_GetInstance();
SINGLETON *instance2 = SINGLETON_GetInstance();
EXPECT_EQ((int)instance1, (int)instance2);
SINGLETON_Destroy(instance1);
SINGLETON_Destroy(instance2);
}
对应图2-2代码如下:
///
//singleton.h
struct _SINGLETON;
typedef struct _SINGLETON SINGLETON;
SINGLETON *SINGLETON_GetInstance(void);
int SINGLETON_Serve(SINGLETON *self);
///
// singleton.c
#include "singleton.h"
struct _SINGLETON
{
char privateData[0];
};
static SINGLETON gInstance = {0};
static void singleton_Init(void)
{
memset(&gInstance, 0, sizeof(SINGLETON));
}
SINGLETON *SINGLETON_GetInstance(void)
{
singleton_Init();
return &gInstance;
}
3、实用类
实用类是无实例的类,它是一组方法的集合。这是网上偶尔看到的,我还不确定“实用类”这一称谓是否通用,有待考究。不过在C程序里面这样的模块应该是最常见的了。如常用库math、string等不妨可理解为实用类。
1、UML示例
2、C代码示例
///
//utility.h
int UTILITY_Serve1(void);
int UTILITY_Serve2(int para);
11点半了~收工睡觉,未完待续……欢迎各位看官留言交流^_^