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

2024-08-30 13:36

本文主要是介绍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文档里有一个很好的例子,我觉得构建成一个树形结构,一个好处就是我们可以将组件的变换定义在其父组件的局部空间中,另一个好处就是更明确了整体和局部的关系。


总结

组合模式的优缺点

优点:

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

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

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

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

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

缺点:

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

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

继承的优缺点

优点:

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

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

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

缺点:

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

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

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

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

这篇关于UE开发中的设计模式(四) —— 组合模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120971

相关文章

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

Java中的Opencv简介与开发环境部署方法

《Java中的Opencv简介与开发环境部署方法》OpenCV是一个开源的计算机视觉和图像处理库,提供了丰富的图像处理算法和工具,它支持多种图像处理和计算机视觉算法,可以用于物体识别与跟踪、图像分割与... 目录1.Opencv简介Opencv的应用2.Java使用OpenCV进行图像操作opencv安装j

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

C#图表开发之Chart详解

《C#图表开发之Chart详解》C#中的Chart控件用于开发图表功能,具有Series和ChartArea两个重要属性,Series属性是SeriesCollection类型,包含多个Series对... 目录OverviChina编程ewSeries类总结OverviewC#中,开发图表功能的控件是Char

鸿蒙开发搭建flutter适配的开发环境

《鸿蒙开发搭建flutter适配的开发环境》文章详细介绍了在Windows系统上如何创建和运行鸿蒙Flutter项目,包括使用flutterdoctor检测环境、创建项目、编译HAP包以及在真机上运... 目录环境搭建创建运行项目打包项目总结环境搭建1.安装 DevEco Studio NEXT IDE

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

hdu4869(逆元+求组合数)

//输入n,m,n表示翻牌的次数,m表示牌的数目,求经过n次操作后共有几种状态#include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdlib.h>#includ