查看原文
其他

嵌入式编程之动态接口技术(经验干货)

bug菌 最后一个bug 2021-01-31

1、把指针分类

  对于具有一定编程经验的同志们都知道指针在C语言编程中算是灵魂和精髓的存在指针的实质就是地址,指针变量就是存储指针的变量。有点绕,简单一点的表达就是用来访问地址内容的一种工具。我们都知道在嵌入式中程序或者数据都是按照地址进行存储和运行的,地址的使用或者地址内容的访问是必不可少的,那么我们的C指针就几乎可以访问到内存中的每个地方,可见指针是如此的灵活,这样对我们开发高效率高技巧性的程序带来了曙光,同样如果我们没有正确的使用指针,对于整个系统都是灾难性的。

 既然使用指针有利有弊,我经常听到有些同志在初学者耳边灌输着尽量不要使用指针的消极思想,一方面我觉得你的个人水平有限误人子弟,同时也为你感到悲哀。好了,废话不多说进入重点:

指针的分类

(在C语言并没有对指针进行分类,该部分知识是自己的平时的理解)

按照指针的作用进行分类。

变量指针:指针指向的类型是一个变量或者是一些变量的集合(如结构体)。

函数指针:指针指向的类型是一个函数。

作者有话说:这里主要是回答为什么会按照这样的方法进行分类,有些C语言书籍里面说程序的组成是函数,而我觉得程序的组成是数据和方法,这里我们把指针分为这样两类变量指针可以认为是数据指针,而我们的函数指针可以认为是方法指针。(好了我们有了这两种指针,程序可以写得飞起来了)

2、编程中动态接口技术

 动态接口技术(不用搜索了,网上找不到这个名词),接口-在大家平时的编程中应该是经常看到或者听到(比如说同事之间配合的一起完成一个项目的软件的时候经常听到"你把接口写好我来调用就行了"!),可见实现一个好的接口对于程序之间是非常重要的。

 那么我们是不是实现越多的接口就越好呢?显然不是这样的,我们昨天提到了软件设计中的"SOLID"原则,其中提到了接口分离,不要太多臃肿。大家可以去看一下那篇对软件设计5大原则的简介。

 动态接口技术,其实就是实现接口的可选择性和兼容性,也就是说我们的接口对于上层服务层来说不发生变化,不过我们所封装的底层却需要可变,可变在我们C语言程序中的表达就是变量的意思。那么普通数据的变化(包括数据内容,数据结构等变化)我们可以选择变量指针(或者说是数据指针);同时我们前面说了,程序是由数据和方法组成,那么我们的方法就由函数指针来取代。好了,下面我以一个实例来对该设计方法进行详细介绍。

3、手把手教你动态接口设计模式

 我们这里就以最简单的兼容多种信号灯驱动程序为例为大家展示该方法。首先我们画一个简易的设计图:

 从上面的结构图来看,上层应用程序访问的是我们的Signal_Light这个抽象的信号灯类型,然而这个信号灯抽象类型包括了三个接口,分别是方法接口,我们打包以后用函数指针即可实现,当我们使用普通Light的使用就只需要注册普通的的Light灯即可,使用高级的Light同样注册即可,往后的项目中可能底层还包括很多的参数使用,我们一方面可以使用数据指针进行选择,同时也可以把数据和方法都进行打包成数据进行注册即可

 参考代码如下:

1)信号灯接口:

  1. //File_Name: Signal_Light.h

  2. /**********************************************

  3. * Decription:信号灯抽象接口

  4. * Author :(公众号:最后一个bug)

  5. *********************************************/

  6. #ifndef __SIGNAL_LIGHT__

  7. #define __SIGNAL_LIGHT__


  8. //接口统一函数指针类型定义

  9. typedef struct _tag_LightInterfaceStruct

  10. {

  11. void (*TurnOn)(void);

  12. void (*TurnOff)(void);

  13. } LightInterfaceStruct;


  14. #endif


  1. //File_Name: Signal_Light.c

  2. /**********************************************

  3. * Decription:信号灯抽象接口

  4. * Author :(公众号:最后一个bug)

  5. *********************************************/

  6. #include "Signal_Light.h"

  7. //信号灯接口

  8. static LightInterfaceStruct lightInterface;


  9. /**********************************************

  10. * Fuction : Register_Signal_Light

  11. * Decription:注册信号灯驱动

  12. * Author :(公众号:最后一个bug)

  13. *********************************************/

  14. void Register_Signal_Light(LightInterfaceStruct Light)

  15. {

  16. lightInterface = Light;

  17. }

  18. /**********************************************

  19. * Fuction : Signal_Light_TurnOn

  20. * Decription:信号灯给上层提供的打开灯服务

  21. * Author :(公众号:最后一个bug)

  22. *********************************************/

  23. void Signal_Light_TurnOn(void)

  24. {

  25. lightInterface.TurnOn();

  26. }

  27. /**********************************************

  28. * Fuction : Signal_Light_TurnOff

  29. * Decription:信号灯给上层提供的关闭灯服务

  30. * Author :(公众号:最后一个bug)

  31. *********************************************/

  32. void Signal_Light_TurnOff(void)

  33. {

  34. lightInterface.TurnOff();

  35. }

2)不同底层函数接口(高级灯和正常灯):

  1. //File_Name: Advan_Light.c

  2. /**********************************************

  3. * Decription:高级灯接口驱动程序

  4. * Author :(公众号:最后一个bug)

  5. *********************************************/

  6. #include"Advan_Light.h"


  7. static void turnOn(void)

  8. {

  9. printf("Advan_light Turn On\n");

  10. }


  11. static void turnOff(void)

  12. {

  13. printf("Advan_light Turn Off\n");

  14. }


  15. LightInterfaceStruct Advan_light =

  16. {

  17. turnOn,

  18. turnOff,

  19. };


  1. //File_Name: Advan_Light.h

  2. /**********************************************

  3. * Decription:高级灯接口驱动程序

  4. * Author :(公众号:最后一个bug)

  5. *********************************************/

  6. #ifndef __ADVAN_LIGHT_H__

  7. #define __ADVAN_LIGHT_H__


  8. #include "Signal_Light.h"


  9. extern LightInterfaceStruct Advan_light;


  10. #endif

  1. //File_Name: Normal_Light.c

  2. /**********************************************

  3. * Decription:普通灯接口驱动程序

  4. * Author :(公众号:最后一个bug)

  5. *********************************************/

  6. #include"Normal_Light.h"


  7. static void turnOn(void)

  8. {

  9. printf("Normal_light Turn On\n");

  10. }


  11. static void turnOff(void)

  12. {

  13. printf("Normal_light Turn Off\n");

  14. }


  15. LightInterfaceStruct Normal_light =

  16. {

  17. turnOn,

  18. turnOff,

  19. };

  1. //File_Name: Normal_Light.h

  2. /**********************************************

  3. * Decription:普通灯接口驱动程序

  4. * Author :(公众号:最后一个bug)

  5. *********************************************/

  6. #ifndef __NORMAL_LIGHT_H__

  7. #define __NORMAL_LIGHT_H__


  8. #include "Signal_Light.h"


  9. extern LightInterfaceStruct Normal_light;


  10. #endif

 3)测试代码

  1. //File_Name: main.c

  2. #include <stdio.h>

  3. #include <stdlib.h>

  4. #include "Normal_Light.h"

  5. #include "Advan_Light.h"


  6. /* run this program using the console pauser or add your own getch, system("pause") or input loop */


  7. int main(int argc, char *argv[]) {


  8. //Main函数定位为上层服务函数


  9. //注册信号灯类型

  10. Register_Signal_Light(Normal_light);

  11. //调用信号灯统一接口

  12. Signal_Light_TurnOff();

  13. Signal_Light_TurnOff();


  14. //注册信号灯接口

  15. Register_Signal_Light(Advan_light);

  16. //调用信号灯统一接口

  17. Signal_Light_TurnOff();

  18. Signal_Light_TurnOff();


  19. printf("欢迎关注公众号:最后一个bug\n");


  20. return 0;

  21. }

 4)测试结果

 好了,今天的干货就分享到这里,这只是一个简单的例子和思路,后续会有跟多的相关的文章更新,欢迎大家关注,这里是公众号:“最后一个bug”,我们下期见!


推荐阅读

单片机常用程序框架之分时轮询(详注代码)

看门狗你确定会用了?(经验干货满满)

单片机开发之节省内存大法(C语言版本)

一种 “ 超强 ” 队列的C语言实现(附代码)

一文搞定通信协议中CRC校验(附代码)

软件设计必备之“SOLID原则”


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存