继承,封装和多态是OOP的三大核心特性,它们共同构了面向对象的基础.但嵌入式开发中大量的使用到的却是C语言这种面向过程的语言,那么我们就需要了解如何在C中使用设计模式的思想做功能开发。要了解设计模式,我们就需要先搞清楚 继承,封装和多态在C语言中应该如何体现。
本系列将会使用一个传感器的例子来说明本节内容。
封装
阿光对封装的理解其实就是将对象的属性和方法高度抽象出来,以传感器为例,传感器的属性可以抽象出传感器类型,传感器数据,采样间隔等,方法可以抽象出获取传感器数据的方法以及打印传感器数据的方法等。
有了以上的抽象,我们就可以定义一个基类来表示传感器
typedef struct Sensor Sensor;
struct Sensor {
const char* type; // 传感器类型
float data; // 传感器数据
int samplingInterval; // 采样间隔(单位:毫秒)
void (*readData)(Sensor* sensor); // 读取数据的方法
void (*printInfo)(Sensor* sensor); // 打印信息的方法
};
创建Sensor对象函数:(基类构造函数)
Sensor* Sensor_create(const char* type, int samplingInterval) {
Sensor* sensor = (Sensor*)malloc(sizeof(Sensor));
sensor->type = type;
sensor->samplingInterval = samplingInterval;
sensor->data = 0.0;
sensor->readData = Sensor_readData; // 默认读取数据方法
sensor->printInfo = Sensor_printInfo; // 默认打印信息方法
return sensor;
}
销毁Sensor对象函数:(基类析构函数)
void Sensor_destroy(Sensor* sensor) {
free(sensor);
}
以上是对基类的封装,通过封装可以使用基类的方法访问数据,杜绝了直接访问数据的情况,可以有效地做到数据安全和保护。同时封装使得类的内部实现细节对外部透明,那么对于类的属性方法的修改不会影响到外部代码实现,更加方便代码的维护和扩展。同时用户也无需关心传感器数据的内部存储和操作细节,只需通过调用方法即可完成功能。
继承
那么我们假设现在有两款传感器(对象),一款是温度传感器,一款湿度传感器;两个传感器都具有基类的所有属性,但是又会有一些差别,比如温度传感器一般会有最高和对低温的限制,同时对于湿度传感器的话我们可以假定一个适宜的湿度范围为人类的舒适区。那么对于两个对象我们可以分别定义两个派生类:
// 定义一个派生类 TemperatureSensor,用于表示温度传感器
typedef struct TemperatureSensor TemperatureSensor;
struct TemperatureSensor {
Sensor sensor; // 继承自 Sensor
float maxTemp; // 最高温度
float minTemp; // 最低温度
};
// 同理,可以定义 HumiditySensor 类来表示湿度传感器
typedef struct HumiditySensor HumiditySensor;
struct HumiditySensor {
Sensor sensor; // 继承自 Sensor
float comfortLevel; // 舒适度
};
那么同样的对于派生类我们需要定义构造和析构函数,以及操作对象的方法。
// 创建 TemperatureSensor 对象的函数
TemperatureSensor* TemperatureSensor_create(int samplingInterval,
float maxTemp, float minTemp)
// 销毁 TemperatureSensor 对象的函数
void TemperatureSensor_destroy(TemperatureSensor* tempSensor)
// 温度传感器的读取数据方法
void TemperatureSensor_readData(Sensor* sensor)
HumiditySensor* HumiditySensor_create(int samplingInterval, float comfortLevel)
void HumiditySensor_destroy(HumiditySensor* humiditySensor)
void HumiditySensor_readData(Sensor* sensor)
以上便是继承的概念在嵌入式开发中一个例子,不同的传感器对象继承了基类的属性,使得代码具有很好的复用性和扩展性,如果有新增的图像传感器依然可以继承基类的属性且只需要单独定义图像传感器的差异属性,这使得代码各个模块之间相互独立,易于后期维护和扩展。
多态
多态的概念:多态允许对象在继承体系中根据需要动态地表现出不同的行为。通过多态,调用者可以通过一个统一的接口来调用不同对象的具体实现,而无需关心对象的实际类型。
即我们可以通过基类指针调用不同派生类的方法。用到上面的例子中我们就可以这样理解:在一个接口内部,可以通过基类Sensor指针来调用温度和湿度传感器的方法。
int main() {
// 创建不同类型的传感器对象
Sensor* sensors[2];
sensors[0] = (Sensor*)TemperatureSensor_create(1000, 45.0, 15.0);
sensors[1] = (Sensor*)HumiditySensor_create(2000, 60.0);
// 多态调用,读取数据并打印信息
for (int i = 0; i < 2; i++) {
sensors[i]->readData(sensors[i]);
sensors[i]->printInfo(sensors[i]);
}
// 销毁对象
TemperatureSensor_destroy((TemperatureSensor*)sensors[0]);
HumiditySensor_destroy((HumiditySensor*)sensors[1]);
return0;
}
以上便是C语言中模拟面向对象中多态的特性,多态使得不同的对象可以使用同一接口实现不同的行为,调用者不需要知道对象的具体类型,只需要知道调用对象的方法即可。做到了各个模块之间解耦。
总结
面向对象的变成模型是设计模式的基础,这种思想将具体的系统分解为独立的对象或类,每个对象负责特定的功能。这种模块化的思想会使得代码的功能更加清晰和易于维护。在后续的简单工厂模式,策略模式等等设计模式中都有很好的体现,这对于嵌入式应用或者驱动开发来说,都是很好的实践。