ECS、代码抽象、继承与组合 杂谈

版权声明:本文为博主原创文章,欢迎转载。请保留博主链接:http://blog.csdn.net/andrewfan https://blog.csdn.net/AndrewFan/article/details/90740062

案例分析:
现在有一个类A,近300行代码,10成员,20个方法,类A中的大部分成员变量和函数在子类中或者业务代码中都可能需要修改,其中有一个方法用到了业务逻辑,具体说就是用到了业务中肯定会变化的一个类,现在要将这个业务逻辑代码分离出去。这种情况下,怎么抽离?抽离时使用继承还是组合?更具体点谁就是is A和has A的问题,具体用哪一个好?还是怎么用好?

组合和继承:
二者各有利弊,以下是我对这种抽象方式的理解:
1、继承的优缺点:
A、优点很多,代码结构简洁,基本不需要增加太多的代码,对于框架的内容实现更可控,可控地暴露功能接口给子类,即便那些内部实现的函数出现问题,而内部出现问题修复时也不需要改变子类。
B、缺点是由于无法多重继承,当子类需要多种组合功能时,无法实现

2、组合的优缺点:
A、优点正好是继承的不足,它可以将多种功能组合起来
B、缺点是,需要增加代码的定义,可以想象一下,如果前面举的例子中,采用组合时,是不是要增加一个类,包装那将近20个左右的函数

继承和组合使用区别情况的举例:
假设要设计一类事物,假设最顶层的概念是动物,动物最基本的一些概念,比如可以移动、可以进食、休息、这些都是动物最基本的属性,按人的思维最直接可以想到这些应该是放在一起的。然后假设有了子概念,比如说是鸟、鱼,鱼可以游泳,鸟可以飞翔,它们自然继承子动物。但是接下来又设计了人这个概念,人由于很强大,所以即可以飞翔,又可以游泳,这个时候就没有办法重用鸟和鱼类中之前实现的功能。此时,出现人的概念的那一刻,就意味着,针对游泳和飞翔的功能,需要使用组合实现,那么接下来我们可以分离一下这种功能。分离方法是,将人、鱼、鸟身上都设置多个插槽,插槽代表了可以接受额外的超能力,那么将飞翔、游泳设定为能力的子类,在初始化人的时候,将飞翔的能力和游泳的能力均安装到人的插槽上,这样就实现了代码的重用。
然而,我们不应该因噎废食,说我既然什么都可以用插槽,那么一切都用插槽,这样会导致代码结构非常复杂,因为每种插槽对应的就是一种新的类型,太多的类很难掌控。

关于ECS与继承组合之间的关系:
我也说一下个人见解,虽然没怎么实践过,不过整个文档也都翻译了也算有些了解。ECS的优点很多,这就不说了,大家都知道,其中解耦合不是它的初衷,确是附带结果,这点也是好的。但是缺点也很明显,就是太复杂,太复杂是如何产生的?就是因为它将所有的功能拆成一个个非常琐碎的子系统,再想去统一这些子系统之间的调度顺序,将变得异常复杂,况且ECS是反对你System之间直接调用的,也就是每个System都尽可能保持独立性,从每个System内部,你也不能直接去拿其它System的实例这一点就可以看出来,也就是说对于我们写A has B这种形式,对应在ECS里面AB都是系统,必然对应各自的组件数据,而通过A持有B去实现的那些功能,他们必然访问了同一个组件数据,这时候AB系统之间就可能产生同步点,很难保持独立性,因此可以说ECS不支持这种组合方式,而是它将功能细分,每个功能系统保持独立,保持独立的意思是只处理自己关心的数据,不与外部打交道,那么当要与外部交互式,也不是直接调用系统来交互,而是通过一些公共的状态组件去交互。所以看得出来这个过程会比较复杂。

整体总结:

所以到了ECS,系统之间的组合基本不存在,但仍然是可以继承的,这也是将来实现代码抽象化的主要方式。当然,从整体上说,它实现的是整个代码级别的组合,因为只要实体中有增加了组件数据,就获得了对应的处理系统,这种组合方式跟传统has A也完全不同。不管如何,这种方式的代码复杂度是增加很多的,要考虑的是如何保持不同系统之间的独立性的同时,父子系统之间代码还可以重用,不同类系统之间还需要保持正确的顺序来通过共享组件交互,这个确实不容易。

展开阅读全文

没有更多推荐了,返回首页