8
回答
哈,对象很重要,结构是形式。喷个技术水帖。。。
华为云4核8G,高性能云服务器,免费试用   

这两天抽空整理了下代码。用这个水帖把我的处理过程水一下,以供oscer们参考,无论是负面的案例,还是正面的案例。哈。 顺带说一句,从价值角度,道理大于方法,方法大于方案,方案大于实例。 一些小朋友喷osc技术讨论内容少,其实我觉得,反倒一些有价值的道理描述的帖子互动少。结果呢,一则我也没看到啥好的讨论贴,二则,把我们 @宏哥 这样的技术大牛,硬生生的憋出了“两个凡是”。 哈。所以水个价值不是太大的“方案”级别的帖子。

一、问题篇

自控系统,可以看作一个轮训控制。简单说,一个大while 循环,定期去干各种事情,可以理解成单线计算下模拟并发处理的工作。 具体的实例是,有一组按键信息,周期的要检测,检测出来,会对应多种不同的控制模式,并执行对应模式。每个执行模式之间是互斥的,有优先级的。整体的代码近似于

while(1){
      ... //处理周期内的预处理工作
      pad_check();//检测按键信息
      mission_done();//根据按键信息处理对应模式
      ... //处理周期内的收尾工作
   }




注明:以上包括本贴随后的代码,是随手写的,而不是基于我的工程代码的摘抄。所以不要考虑可编译性。哈。

二、对象篇

这里还是重复一个观点。面向对象的分析和利用面向对象语言的编程是两回事。不用面向对象语言来编程仍然需要面向对象的分析。不进行面向对象的分析,你就是用了面向对象语言的编程也是扯淡。哈。同时“对象”并不代表一定是个实物。一个我自己的表述,“可结构化表述,具有特定运行机理的一类逻辑组合的具体化,则为对象”,这句话有点绕以及太抽象,估计会被喷,哈,无所谓。只是想表明“对象”不是特指以实物形式存在的东西。例如企业的一套组织管理流程,也可以看作一种“对象”,它有相对固化的结构表述和处理机制,是一组逻辑组合的具体化。

回到正题,对于互斥的执行模式,例如,我们的车体是四驱的,我可以有三个执行模式,刹/停车,匀速运动,航向锁定。你在执行“刹/停车”时,就不要去考虑还能执行“匀速运动”。 这些执行模式,就可以看作“对象”。每个对象,此时包括了,“入口函数”和“执行参数”,两个内容。因此最简单的结构表述如下:

typedef int(*_MISSION_DONE_FUNC)(void*pinfo);

typedef struct{
	_MISSION_DONE_FUNC pfunc;
	void *pinfo;
        ...
}_MISSION_MODE;



哈, 不怕人喷我说“这也叫面向对象编程”,我最多回一句“这咋不叫面向对象编程”。这里使用 void *,是因为不同执行模式的处理函数,对应的信息结构并不一致,那么抽象的,就直接是指针类型来引用即可。只要外部对执行控制信息的处理与对应执行函数内的信息获取,在数据结构上是一致的即可。

对应的另一个对象则是“键盘信息检测”。 一种典型的初级程序员的思维如下(假设存在6个按键,上下左右,和功能a,b键)

void pad_check(void){
     mode = _STOP_MODE; //默认为刹/停车模式
     if (up) || (down) || (left) ||(right){
       mode = _MOVE_MODE; //匀速运动模式
       ... //一堆执行信息的分析和配置
     }
     if (a)||(b){
       mode = _ANGLE_MODE; //航向锁定模式
       ... //一堆执行信息的配置
     }
     ...

}



上述代码的描述是过程化的设计思维。没啥水平高低之分。对于新系统,前期功能的实践(没有分析清楚对象结构时)我也这么写,因为快啊,考虑那么全不可能,不做事也不可能。但上述就不是面向对象的分析。

面向对象的分析,我们可以这么抽象的理解,假设有三个(虚拟)的人,停/刹车,匀速,航向锁定的指挥员。他们共同看一个套按键信息,每个人都从信息中找到自己需要的,例如匀速的只需要看up,down ...等等,航向锁定的,只需要看 a,b 等等。此时,将这三个指挥员的工作和他们需要记录的信息结构化组合起来,则是对象。

则类似mission_done有如下代码:

typedef int(*_PAD_CHECK_FUNC)(void*pinfo);

typedef struct{
	_PAD_CHECK_FUNC pfunc;
	void *pinfo;
        ...
}_PAD_CHECK;



上面可以看作某类对象的基本组成。余下则是具体化的工作。例如
enum{
   _STOP_MODE,
   _MOVE_MODE,
   _ANGLE_MODE,
   _MAX_CTL_MODE_NUM
};
typedef struct{
...
}_STOP_INFO_STRUCT ; //刹停车模式对应信息结构体
typedef struct{
...
}_MOVE_INFO_STRUCT ;  //匀速运动对应信息结构体
typedef struct{
... 
}_ANGLE_INFO_STRUCT; //航向锁定对应信息结构体
static _STOP_INFO_STRUCT s_stop_info[1]; //信息数据空间定义,[1]是方便引用
static _MOVE_INFO_STRUCT s_move_info[1];//信息数据空间定义,[1]是方便引用
static _ANGLE_INFO_STRUCT s_angle_info[1];//信息数据空间定义,[1]是方便引用
static int _check_stop(void*pinfo);// 函数接口申明
static int _check_move(void*pinfo);// 函数接口申明
static int _check_angle(void*pinfo);// 函数接口申明

static _PAD_CHECK pad_check[_MAX_CTL_MODE_NUM] = { //定义每个具体对象并绑定数据和处理函数入口
   {_check_stop,(void*)(s_stop_info)},
   {_check_move,(void*)(s_move_info)},
   {_check_angle,(void*)(s_angle_info)},
};
static int _check_stop(void*pinfo){ //具体实现
   int re = 0;
   s_stop_info *p = (s_stop_info*)pinto;
   ...
   return re;
}
...



上述对象化的处理,可以通过代码范式化的设计,降低模式调整时代码的修增范围。例如我们后续增加其他的执行控制,则可参照已有的,分别针对键盘信息检测和执行模式,进行扩充,而不需要改动已有模式的代码,例如:
enum{
  _STOP_MODE ,
  ...
  _NEW_MODE, //此处增加新的模式
  _MAX_CTL_MODE_NUM
};

...//这里各种新增。。

void pad_check(void){//此函数就不存在任何改动
  int i;
   for (i = 0 ; i  < _MAX_CTL_MODE_NUM ;i++){
       s_pad_check[i].pfunc(s_pad_check[i].pinfo);
   }
}



再用另一种表述就是,我们有一类的键盘信息分析工作。将其对象化,形成一种类型。 

哈。可能估计有人要喷,用面向对象语言,可以做的更简单,然后巴拉巴拉的各种例子。我只能说,看每个人对不同语言的熟练度吧。就我个人,还是觉得用c更顺手。哈。

三、关联篇

这里不谈啥父子继承的关联。而是指,同一类的对象之间存在关联,回到执行模式上。这里说个具体的例子,例如,我们控制一个车辆前进时,同时按下按键a,则立刻执行航向锁定,比如左转90度,此时就存在几个问题。首先的问题是,航向锁定有更高优先级。如同前面说的,三个不同的指挥员,通过键盘信息确定了三个不同的指挥要求时,他们之间也有优先级高低。

对象之间优先级的实现,可以有多种策略。对应的是算法问题,而算法即要面对数据结构(对象数据组织的结构形式),也需要特定的数据结构来支撑。一种简单的处理方式则是固化优先级。和键盘分析的对象一样,我们可以有类似执行模式的对象组织,如下:

static int _mission_bldc_stop(void*pinfo);// 函数接口申明
static int _mission_bldc_move(void*pinfo);// 函数接口申明
static int _mission_bldc_angle(void*pinfo);// 函数接口申明

static _MISSION_MODE s_mission_bldc[_MAX_CTL_MODE_NUM] = { //定义每个具体对象并绑定数据和处理函数入口
   {_mission_bldc_stop,0},
   {_mission_bldc_move,0},
   {_mission_bldc_angle,0},
};
static int _mission_bldc_stop(void*pinfo){ //具体实现
   int re = 0;
   s_stop_info *p = (s_stop_info*)pinto;
   ...
   return re;
}
...



这里,对于
mission_bldc[i].pinfo

的初始化,则是设置为0 ,因为对于带有优先级的执行控制,有如下处理策略,代码:

for (i = _MAX_CTL_MODE_NUM -1; i > 0 ; i--){
   if (s_mission_bldc[i].pinfo){
      s_mission_bldc[i].pfunc(s_mission_bldc[i].pinfo);
       break;
   }
}
if (i == 0){ //如果什么模式都没有调度,则调度默认的停止模式
   s_mission_bldc[i]. pfunc(s_mission_bldc[i].pinfo);
}else{//清除低i优先级的控制信息
   mission_bldc_clean(i);
}



这样的控制策略是指,根据pinfo是否为0,判断当前执行模式是否存在,不存在则去判断更低优先级的执行模式。 此时,处理策略和对象类型中的数据组织结构有关联。对应的在键盘检测信息中,自然会要存在如下代码:

static int _check_move(void*pinfo){ //具体实现
   int re = 0;
   s_stop_info *p = (s_stop_info*)pinto;
   ...
   s_mission_bldc[_MOVE_MODE].pinfo = p; //设置对应执行模式中的参数指针
   return re;
}



上面有个 , s_mission_bldc[_MOVE_MODE].pinfo = p ;的代码,这是两种类型对象之间进行关联的处理工作。其实用如下方式处理更好:
void pad_check(void){//此函数就不存在任何改动
  int i;
   for (i = 0 ; i  < _MAX_CTL_MODE_NUM ;i++){
       if (s_pad_check[i].pfunc(s_pad_check[i].pinfo)){
          s_misson_bldc[i].pinfo = s_pad_check[i].pinfo;
   }
}



当然随着你的业务分析的展开,会有很多其他设计目标,上述的算法策略和代码组织方式仍然可以调整,这里就不一一讨论了。哈。

四、总结篇

对象很重要,无论你是啥名词,其实我一直是“模块”派的簇拥者。 模块化设计思想,是我的指导方向。模块化也是一种“对象化”。无论如何,对象很重要。 对象分析后,具体的组织结构方式,则是一个形式。哈。一如既往的,在水帖最后,喷一喷。。。这次仍然喷语言。不喷语言,没眼球效应啊。 一句话:

无论你用哪种语言,没有好坏,对错。只有是否适合你的业务背景一说。 如果你以为掌握了一门语言的语法规则,就可行走江湖打遍天下了。我没啥说的,事实会教育你,还早呢。  语言语法,结构表述都是形式,外招,武功还要练就内功。内力高低,在于你对业务的理解和分析后,在对象与类的构建上水平上。语言和衣服一样,用不用这个语言,在于心情和是否满足需求。靠穿个名牌衣服体现自己高大上,甚至标签都不剪,逢人就展示标签价格,只能说你太low 。。。哈。

补充说一句, @宏哥 被喷,你丫是活该。因为宏哥的帖子太抽象到没任何营养,但喷宏哥的,恐怕多少不了解宏哥的技术水平。 当然话多话少,都会被碰,这属于活该,哈。他是话少,我是话多,我被碰也是活该,哈。喷无所谓,权当取乐,大家不要上纲上线就好。言论自由嘛。哈。









<无标签>
举报
中山野鬼
发帖于2年前 8回/366阅
共有8个回帖 最后回答: 2年前

你说辣么多,其实所谓的对象不对象,就是【抽象】的意思,不管面向什么,都要对解决的问题进行抽象。所谓抽象,就是取所研究问题的某些片面,合成一个原理。

剩下的一大堆,其实都是在说你的业务而已。if(LEFT && RIGHT)...else if(RIGHT)...这样的写法并非很low,只是满足不了你的需求罢了。

引用来自“乌龟壳”的评论

你说辣么多,其实所谓的对象不对象,就是【抽象】的意思,不管面向什么,都要对解决的问题进行抽象。所谓抽象,就是取所研究问题的某些片面,合成一个原理。

剩下的一大堆,其实都是在说你的业务而已。if(LEFT && RIGHT)...else if(RIGHT)...这样的写法并非很low,只是满足不了你的需求罢了。

不同判断处理的工作,集中在一个函数中统一处理,是一个比较传统的,也是个不太合理的处理方式。肯定low,但是low在某些情况下,最实用。哈。  不说辣么多,则又成谈虚的。。。哈。刚好理理思路。
--- 共有 7 条评论 ---
dy810810回复 @中山野鬼 : 怂 2年前 回复
中山野鬼回复 @dy810810 : 哈,首先 乌龟壳的具体问题在哪?貌似没有问题吧。 其次,怎么才算正面回答? 最后,是否正面回答,是我的自由吧? 2年前 回复
dy810810回复 @中山野鬼 : 你还是没有认真回答@乌龟壳 的问题。 2年前 回复
中山野鬼回复 @dy810810 : 哈,不懂的领域就是不懂,就不扯淡了。抽象点?貌似我的一半的帖子别这个帖子抽象,欢迎讨论,如上一篇水帖,关于系统的。。 2年前 回复
乌龟壳回复 @dy810810 : 人家只是来闲扯的,哈 2年前 回复

开发效率很重要, 最近一个朋友的机器人,已经申请专利的情况下, 有大公司根据 专利申请内容,直接实现了新款。

用C开发,在大多时候,确实落后了。

考虑一下luajit .

--- 共有 3 条评论 ---
dy810810回复 @宏哥 : 没问题啊,你可以去告啊。。。为什么不告?为什么不申诉? 2年前 回复
宏哥回复 @dy810810 : 你看清楚没? 专利已经申请了, 有专利号的 2年前 回复
dy810810你这就是瞎扯。你会curd,别人也会啊,你申请专利了吗?说到底不就是没自己的核心技术嘛。专利说出来吓谁啊?你搞清楚专利的三大分类了吗? 1.发明。2.创造。3外观。 想清楚了吗?瞎回复什么? 2年前 回复

对象就是结构+算法

实际上, 算法 和结构互相独立依赖

弱耦合高内聚要求 结构有灵活性  和 算法要进行分离而非强绑定,但是算法依赖结构设计。

对象大多情况没有太多意义。


可结构化表述,具有特定运行机理的一类逻辑组合的具体化,则为对象”  还是比较赞的 。 

“可结合化表述,具有特定的组成机理的一类逻辑组合,则为对象”  具体的抽象的都可以有的

个人认为对象是一种思考问题的方式,而语言是否直接支持对象的特性只是会影响到写代码这个人的速度:比如用他用Ada可以一个小时搞定的事情,换成C可能就需要一天。

同理,对于对象的理解不应当只局限于语言层面。赞同可结构化表述,具有特定运行机理的一类逻辑组合的具体化,则为对象这句话。或者可以这么说:将具有相同行为或者属性的一类物体即可称为对象。Linux中对于文件系统的抽象即使如此。然而抽象层所带来的时间(cache不友好)和空间(抽象层的空间)消耗也是需要权衡的问题之一,所以到底用不用面向对象,也是要根据具体生产环境进行确定的。

例如面对一个可能扩展的生产环境来说(例如操作系统内核、不同的文件系统、网络协议等),就可以考虑使用一个抽象层进行抽象,以方便以后的扩展(内核模块、VFS、Socket等)。至于具体怎么实现扩展,不同的理解会有不同的实现方式(宏内核的Linux使用了内核模块实现扩展,BSD等通过独立模块之间的通信等等),这里不必要在意哪种是真正的模块化,只要能够有效地解决需求,那就够了。

然而面对一个相对单一的需求(更多的是单片机上,控制某个简单的流程),因为条件等等各种情况的限制(例如计算能力),不适宜或者不必要按照对象来进行分类,那就不去折腾了。一句printf("Hello world!\n");能解决的问题,为啥非要可以找出成百上千的类,然后以各种奇葩的姿势去输出这么一个简单的字符串(各种练习题,挑战赛或其它奇葩情况除外)?

(无意引战,仅表述个人观点,如与前辈们的观点不一致,还请轻拍)

顶部