UE开发中的设计模式(四) —— 组合模式

面试中被面试官问到组合模式和继承有什么区别,给我问懵了,今天又仔细看了下,这不就是UE里的组件吗 >_<



问题提出

考虑这样一个场景,我们有一个敌人的基类,其包含一些公有的属性和方法,比如他有一个Mesh(Static Mesh/Skeletal Mesh),他在世界空间中有一个位置,他可以攻击我们的玩家。然而对于不同类型的敌人,他可能有自己独特的属性和方法,比如有些怪可以给己方加血,有些怪会飞,有些怪会上buff…

一种常见的设计方法是通过继承实现。

从上面的UML图可以看出,EnemyClassA 可以飞,可以上buff,EnemyClassB 可以上 buff,可以治疗队友,EnemyClassC 可以治疗队友,可以飞。想象一下,如果再有一个新的方法,比如可以隐身,那么可能又会产生三个新的基类(考虑两种独有的方法),但其实完全不必要,因为fly,buff,treat明显是重复实现了好多次。

那么有什么办法可以解决这个问题吗。


概述

这时候就需要组合模式闪亮登场了,组合模式通过少继承多组合的方式,可以提高代码复用,且我们想给一个类增加一个新功能,直接给他加一个组件就行了,很方便。

在UE/Unity里也是用了组件,比如UE里的移动组件,网格组件,摄像机组件,一个Actor可以说是一个组件的容器,组件给Actor提供了各种技能。

且组件也支持嵌套,即组件可以包含很多的子组件,比如UE里的USceneComponent,其有一个AttachParent为父节点,还有一个AttachChildren保存多个子节点,明显是一个树形结构。这种设计哲学,感觉更像是这些组件组合起来,成为了一个我们想要的类,而不是像继承一样,通过分类的方式,子类相较于父类多了什么。


这种设计模式也很适合用来设计UI,UI本身也可以看作一个树形结构,每一个组件提供了一些功能,其下也能包含其它的一些小的组件。


问题解决

我们用组合的方式来解决一开始敌人的场景问题,我们可以有飞行组件、治疗组件、加buff组件,那么对于一个具体的敌人,我们只需要添加对应的组件即可。

这个场景比较简单,且有明显的继承关系,个人感觉其实用继承更合适。但其实好多类他们没有继承关系,比如玩家和敌人,没有明显的继承关系,但都可以行走,那么完全可以独立出一个移动组件,而UE本身也是这么做的。

而且组合模式,可以动态地增减节点,对应的就是增加/减少功能,更加灵活(更低的耦合)。比如玩家捡到一把枪,那么玩家就获得了开火射击的技能。枪也相当于组件挂载到玩家这个整体组件的树形结构上。

UE文档里有一个很好的例子,我觉得构建成一个树形结构,一个好处就是我们可以将组件的变换定义在其父组件的局部空间中,另一个好处就是更明确了整体和局部的关系。


总结

组合模式的优缺点

优点:

  • 灵活性高: 组合模式允许在运行时动态地改变对象的行为,比继承这种在编译时确定的机制更为灵活。

  • 减少耦合: 通过组合,类与类之间的关系可以保持松散耦合,有利于系统的可维护性和可扩展性。

  • 更好的代码复用: 对象可以通过组合不同的小对象来获得新的功能,而不需要从基类继承所有的实现。这有助于代码模块化和复用。

  • 更容易进行单元测试: 由于组合的各个组件是分离的,这些组件可以单独进行测试,简化了测试过程。

  • 避免继承层次复杂: 大量使用继承可能导致复杂的继承层次结构,使得系统难以理解和维护。组合模式通过简单组合对象,避免了这个问题。

缺点:

  • 复杂性增加: 组合模式可能会导致系统设计复杂化,因为需要管理更多的对象和对象关系。

  • 接口定义可能复杂: 为了支持组合,各个组件之间需要定义良好的接口。这些接口的定义和维护可能会比较复杂。

继承的优缺点

优点:

  • 直接性: 继承是直观的、简单的,特别是在机制已经被明确时。它允许一个类自动获得另一个类的属性和方法。

  • 基础实现共享: 继承允许子类共享从基类继承的代码,因此可以较容易实现代码复用。

  • 一致性: 通过继承可以确保子类与父类之间的一致性,子类可以覆盖或扩展父类的方法。

缺点:

  • 灵活性较差: 继承的关系在编译时已经确定,因此运行时无法进行动态行为改变。

  • 高耦合: 继承会导致子类和父类之间的紧耦合关系,增加了系统变化的难度。如果父类发生变化,可能会影响所有子类。

  • 继承层次复杂难以管理: 继承层次过深时,会导致代码维护困难,理解和管理的成本增加。

  • 单继承的限制: 在不支持多重继承的语言中,继承会限制一个类只能从一个父类继承,限制了类之间的关系构建。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值