组件式设计

在代码复用和组织数据方面,面向对象可能是大家第一反应。面向对象三大特性继承,封装,多态,在一定程度上能解决不少代码复用,数据复用的问题。不过面向对象不是万能的,它也有极大的缺陷:

1. 数据结构耦合性极强

一旦父类中增加或删除某个字段,可能要影响到所有子类,影响到所有子类相关的逻辑。这显得非常不灵活,在一套复杂的继承体系中,往父类中改变字段会变得越来越麻烦,比方说ABC是D的子类,某天发现需要增加一个AB都有的数据,但是C没有,那么这个数据肯定不好放到父类中,只能将AB抽象出来一个父类E,E继承于D,AB共有的字段加到E中,一旦继承结构发生了变化,可能接口也要改变,比方说之前有个接口传入参数类型是E,当AB不再需要共用的那个字段,那么需要调整继承关系,让AB重新继承D,那么这个接口的传入参数类型需要改成D,其中的逻辑代码很可能也要发生调整。更可怕的是游戏逻辑变化非常复杂,非常频繁,可能今天加了个字段,明天又删掉了,假如每次都要去调整继承结构,这简直就是噩梦。继承结构面对频繁的数据结构调整感觉很无力。

2. 难以热插拔

继承结构无法运行时增加删除字段,比如玩家Player平常是走路,使用坐骑后就骑马。问题是坐骑的相关信息就需要一直挂在Player对象上面。这就显得很不灵活,我不骑马的时候内存中为啥要有马的数据?接口也有同样的问题,一个类实现了一个接口,那么这个接口就永远粘在了这个类身上,你想甩掉她都不行,还是以骑马为例,玩家Player可以进行骑行,那么可能继承一个骑行的接口,问题是,当我这个Player从坐骑上下来时,玩家Player身上还是有骑行的接口,根本没法动态删掉这个接口!可能例子举得不是很对,但是道理表述的应该很清楚了。

使用面向对象可能导致灾难性后果,游戏开发中有新人有老人,有技术好的,有技术差的。人都是喜欢偷懒的,当你发现调整继承关系麻烦的时候,有可能AB中增加一个字段为了省事直接就放到父类D中去了。导致C莫名奇妙的多了一个无用的字段。关键还没法发现,最后导致父类D越来越大,到最后有可能干脆就不用ABC了,直接让所有对象都变成D,方便嘛!是的,很多游戏就是这么干的,开发到最后根本就不管继承关系了,因为想管也管不了了。

3. 方法与数据耦合

传统面向对象都是class中带有方法,并且特别提倡虚函数多态。方法跟数据放在一起带来了特别多耦合的问题。为了解决这些耦合,大家想出了大量的设计模式,比如依赖接口,依赖转置。说实话,这就是脱裤子放屁,为了解耦合,把类做成接口,然后继承接口,难道这就不叫依赖了?这些做法导致,代码中到处是接口,代码阅读极其困难。写起代码来也没有个标准,高手跟菜鸡写出来的代码完全是两回事。大部分码农都是逻辑仔,谁有时间天天想这个类要怎么设计啊?随着逻辑越来越复杂类里面的方法将越来越庞大,可怕的是,这是这个类的方法,极其难以重构,很多项目中能看到类里面存在上万行代码的虚函数。天哪!

面向对象在面对复杂的游戏逻辑时很无力,所以很多游戏开发者又倒退了回去,使用面向过程进行开发游戏,面向过程,简单粗暴,不考虑复杂的继承,不考虑抽象,不考虑多态,是开发届的freestyle,挽起袖子就开撸,但同时,代码逻辑的复用性,数据的复用性也大大降低。面向过程也不是一种好的游戏开发模式。

组件模式很好的解决了面向对象以及面向过程的种种缺陷,在游戏客户端中使用非常广泛,Unity3d,虚幻4,等等都使用了组件模式。组件模式的特点: 1.高度模块化,一个组件就是一份数据加一段逻辑
2.组件可热插拔,需要就加上,不需要就删除
3.类型之间依赖极少,任何类型增加或删除组件不会影响到其它类型。

但是目前只有极少有服务端使用了组件的设计,守望先锋服务端应该是使用了组件的设计,守望先锋的开发人员称之为ECS架构,其实就是组件模式的一个变种,E就是Entity,C就是Component,S是System,其实就是将组件Component的逻辑与数据剥离,逻辑部分叫System,话题扯远了,还是回到ET框架来把。

ET框架使用了组件的设计。一切都是Entity和Component,任何类继承于Entity都可以挂载组件,例如玩家类:

public sealed class Player : Entity
{
public string Account { get; private set; }
public long UnitId { get; set; } public void Awake(string account)
{
this.Account = account;
} public override void Dispose()
{
if (this.Id == 0)
{
return;
}
base.Dispose();
}
}

给玩家对象挂载个移动组件MoveComponent,这样玩家就可以移动了,给玩家挂上一个背包组件,玩家就可以管理物品了,给玩家挂上技能组件,那么玩家就可以施放技能了,加上Buff组件就可以管理buff了。

player.AddComponent<MoveComponent>();
player.AddComponent<ItemsComponent>();
player.AddComponent<SpellComponent>();
player.AddComponent<BuffComponent>();

组件是高度可以复用的,比如一个NPC,他也可以移动,给NPC也挂上MoveComponent就行了,有的NPC也可以施放技能,那么给它挂上SpellComponent,NPC不需要背包,那么就不用挂ItemsComponent了

ET框架模块全部做成了组件的形式,一个进程也是由不同的组件拼接而成。比方说Loginserver需要对外连接也需要与服务器内部进行连接,那么login server挂上

// 内网网络组件NetInnerComponent,处理对内网连接
Game.Scene.AddComponent<NetInnerComponent, string, int>(innerConfig.Host, innerConfig.Port);
// 外网网络组件NetOuterComponent,处理与客户端连接
Game.Scene.AddComponent<NetOuterComponent, string, int>(outerConfig.Host, outerConfig.Port);

比如battle server就不需要对外网连接(外网消息由gateserver转发),那么很自然的只需要挂载一个内网组件即可。 类似Unity3d的组件,ET框架也提供了组件事件,例如Awake,Start,Update等。要给一个Component或者Entity加上这些事件,必须写一个辅助类。比如NetInnerComponent组件需要Awake跟Update方法,那么添加一个这样的类即可:

[ObjectEvent]
public class NetInnerComponentEvent : ObjectEvent<NetInnerComponent>, IAwake, IUpdate
{
public void Awake()
{
this.Get().Awake();
} public void Update()
{
this.Get().Update();
}
}

这样,NetInnerComponent在AddComponent之后会调用其Awake方法,并且每帧调用Update方法。 ET没有像Unity使用反射去实现这种功能,因为反射性能比较差,而且这样实现的好处是这个类可以放到热更dll中,这样组件的Awake Start,Update方法以及其它方法都可以放到热更层中。将Entity和Component做成没有方法的类,方法都放到热更层,方便热更修复逻辑bug。

组件式开发最大的好处就是不管菜鸟还是高手,开发一个功能都能很快的知道怎么组织数据怎么组织逻辑。可以完全放弃面向对象。使用面向对象开发最头疼的就是我该继承哪个类呢?之前做过最恐怖的就是虚幻三,虚幻三的继承结构非常多层,完全不知道自己需要从哪里开始继承。最后可能导致一个非常小的功能,继承了一个及其巨大的类,这在虚幻三开发中屡见不鲜。所以虚幻4改用了组件模式。组件模式的模块隔离性非常好,技术菜鸟某个组件写得非常差,也不会影响到其它模块,大不了重写这个组件就好了。

ET的组件设计有所创新,方法跟数据分离,完全解除耦合,不用绞尽脑汁去想怎么解除耦合,随意写静态方法即可,根本不存在耦合,即使是菜鸟写的代码也很容易重构。

正是因为ET使用了可拆卸的组件模式,ET可以将所有服务器组件都装到同一个进程上,那么这一个进程就可以当作一组分布式服务器使用。从此用vs调试分布式服务器成为了可能。正因为这样,平常开发只使用一个进程,发布的时候发布成多个进程就行了。说实在的,不是吹牛,这是一个伟大的发明,这一发明解决了分布式游戏服务器开发中的大大大难题,极大的提高了开发效率。

ET开源地址地址:egametang/ET: Unity3D Client And C# Server Framework (github.com)   qq群:474643097

ET介绍——组件式设计(优化版的ECS)的更多相关文章

  1. Unity3d&C#分布式游戏服务器ET框架介绍-组件式设计

    前几天写了<开源分享 Unity3d客户端与C#分布式服务端游戏框架>,受到很多人关注,QQ群几天就加了80多个人.开源这个框架的主要目的也是分享自己设计ET的一些想法,所以我准备写一系列 ...

  2. HBase最佳实践-列族设计优化

    本文转自hbase.收藏学习下. 随着大数据的越来越普及,HBase也变得越来越流行.会用HBase现在已经变的并不困难,然而,怎么把它用的更好却并不简单.那怎么定义'用的好'呢?很简单,在保证系统稳 ...

  3. 第二次讨论——响应式设计、布局技巧、css性能优化、css预处理

    第二次讨论 [响应式设计] 集中创建页面的图片排版大小,可以智能地根据用户行为以及使用的设备环境(系统平台.屏幕尺寸.屏幕定向等)进行相对应的布局. 响应式布局: meta标签的实用:设置布局宽度等于 ...

  4. SuperMap iObject入门开发系列之一组件式GIS开发平台介绍

    本文是一位好友“炀炀”授权给我来发表的,介绍都是他的研究成果,在此,非常感谢.平台介绍:SuperMap iObjects Java/.NET 是面向GIS应用系统开发者的组件式GIS开发平台,具有强 ...

  5. .NET 纯原生实现 Cron 定时任务执行,未依赖第三方组件 (Timer 优化版)

    在上个月写过一篇 .NET 纯原生实现 Cron 定时任务执行,未依赖第三方组件 的文章,当时 CronSchedule 的实现是使用了,每个服务都独立进入到一个 while 循环中,进行定期扫描是否 ...

  6. HTML5实践 -- 使用CSS3 Media Queries实现响应式设计

    CSS3 Media用法介绍:http://www.w3cplus.com/content/css3-media-queries 转载请注明原创地址:http://www.cnblogs.com/so ...

  7. hive介绍及架构设计

    hive介绍及架构设计 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们知道MapReduce和Spark它们提供了高度抽象的编程接口便于用户编写分布式程序,它们具有极好的扩展性 ...

  8. GHOST WIN7系统64位经典优化版 V2016年

    来自系统妈:http://www.xitongma.com 深度技术GHOST win7系统32,64位经典优化版 V2016年3月 系统概述 深度技术ghost win7系统64位经典优化版适用于笔 ...

  9. Agile.Net 组件式开发平台 - 平台系统介绍

    平台介绍 Agile.Net 组件式开发平台是一款针对企业级产品的开发框架,平台架构基于SOA服务体系,多层组件式架构打造.平台提供企业应用开发所需的诸如ORM.IOC.WCF.EBS.SOA等分布式 ...

  10. PIE SDK组件式开发综合运用示例

    1. 功能概述 关于PIE SDK的功能开发,在我们的博客上已经分门别类的进行了展示,点击PIESat博客就可以访问,为了初学者入门,本章节将对从PIE SDK组件式二次开发如何搭建界面.如何综合开发 ...

随机推荐

  1. 关于前端JS的一些常用方法和知识

    关于前端数据存储目前只解释有三种:cookie.localStorage.sessionStorage cookie解释:只针对当前session(会话)有效,关闭标签页即失效使用: 1 var ck ...

  2. Androidstudio连接SQLite数据库报错not such table的相关解决

    错误展示 明明就是按照创建第一个表的步骤来的,然后就是死活创建不出来第二张表,离谱啊家人们! 错误解决 针对于这个错误,只需要在SQLite类里面,将其中的version变量的值更改为更高版本即可: ...

  3. windows 系统下 workerman 在同一个运行窗口中开启多个 websocket 服务

    目录 开启多个 ws 服务失败 开启服务失败解决办法 同一个窗口中运行 开启多个 ws 服务失败 正常情况下,如果你想开启多个 websocket 服务的话 只要在一个文件中,输入 new Worke ...

  4. flutter---->flutter orientation

    Get the orientation 1. Media Query import 'package:flutter/material.dart'; void main() => runApp( ...

  5. Rainbond的 Gateway API 插件制作实践

    Gateway API 作为新一代的流量管理标准,对原有 Ingress 的扩展不规范.移植性差等问题做出了改进.从兼容K8s生态和优化网关体验出发,Rainbond 支持以插件的形式扩展平台网关能力 ...

  6. 使用Electron-builder将web项目封装客户端安装包 发布

    背景:之前用electron-packager将web项目打包成客户端时,exe文件只能在当前文件夹下运行,如果发送给别人使用 极不方便.所以我们可以用electron-builder将web项目封装 ...

  7. freeswitch媒体协商的优先级方案

    概述 freeswitch是一款简单好用的VOIP开源软交换平台. 不同的媒体格式各有优缺点,实际环境中的应用要根据线路和客户的实际需求确定. 本文中介绍一种较为通用的媒体配置方案,可以适配大部分场景 ...

  8. 为什么我推荐你使用 systemd timer 替代 cronjob?

    概述 前几天在使用 Terraform + cloud-init 批量初始化我的实验室 Linux 机器.正好发现有一些定时场景需要使用到 cronjob, 进一步了解到 systemd timer ...

  9. JAVA基础——常用类(一)

     首先认识到--String是不可以变性(final) String:字符串,使用一对""引起来表示.      * 1.String声明为final的,不可被继承      * ...

  10. AI开发实践:关于停车场中车辆识别与跟踪

    摘要:本案例我们使用FairMOT进行车辆检测与跟踪.yolov5进行车牌检测.crnn进行车牌识别,在停车场入口.出口.停车位对车辆进行跟踪与车牌识别,无论停车场路线多复杂,小车在你掌控之中! 本文 ...