简体   繁体   English

C# 关于扩展大型 class 以提高可读性

[英]C# On extending a large class in favor of readability

I have a large abstract class that handles weapons in my game.我有一个大型抽象 class 来处理我的游戏中的武器。 Combat cycles through a list of basic functions:通过一系列基本功能进行战斗循环:

OnBeforeSwing
OnSwing
OnHit || OnMiss

What I have in mind is moving all combat damage-related calculations to another folder that handles just that.我的想法是将所有与战斗伤害相关的计算移到另一个处理该问题的文件夹中。 Combat damage-related calculations.战斗伤害相关的计算。

I was wondering if it would be correct to do so by making the OnHit method an extension one, or what would be the best approach to accomplish this.我想知道通过使OnHit方法成为扩展方法是否正确,或者实现此目的的最佳方法是什么。

Also.还。 Periodically there are portions of the OnHit code that are modified, the hit damage formula is large because it takes into account a lot of conditions like resistances, transformation spells, item bonuses, special properties and other, similar, game elements.定期修改部分 OnHit 代码,命中伤害公式很大,因为它考虑了许多条件,如抗性、变形法术、物品奖励、特殊属性和其他类似的游戏元素。

This ends with a 500 line OnHit function, which kind of horrifies me.这以 500 行 OnHit function 结束,这让我感到恐惧。 Even with region directives it's pretty hard to go through it without getting lost in the maze or even distracting yourself.即使有区域指令,也很难通过它而不迷失在迷宫中甚至分散自己的注意力。

If I were to extend weapons with this function instead of just having the OnHit function, I could try to separate the different portions of the attack into other functions.如果我要使用这个 function 而不是仅仅使用 OnHit function 来扩展武器,我可以尝试将攻击的不同部分分成其他功能。

Then again, maybe I could to that by calling something like CombatSystem.HandleWeaponHit from the OnHit in the weapon class, and not use extension methods.再说一次,也许我可以通过从武器 class 中的 OnHit 调用CombatSystem.HandleWeaponHit之类的东西来实现这一点,而不是使用扩展方法。 It might be more appropriate.可能更合适。

Basically my question is if leaving it like this is really the best solution, or if I could (should?) move this part of the code into an extension method or a separate helper class that handles the damage model, and whether I should try and split the function into smaller "task" functions to improve readability.基本上我的问题是,如果这样离开它真的是最好的解决方案,或者我是否可以(应该?)将这部分代码移动到扩展方法或单独的帮助程序 class 来处理损坏 model,以及我是否应该尝试和将 function 拆分为更小的“任务”函数以提高可读性。

I'm going to go out on a limb and suggest that your engine may not be abstracted enough.我将竭尽全力 go 并建议您的引擎可能不够抽象。 Mind you, I'm suggesting this without knowing anything else about your system aside from what you've told me in the OP.请注意,除了您在 OP 中告诉我的内容之外,我在不了解您的系统的任何其他内容的情况下提出此建议。

In similar systems that I've designed, there were Actions and Effects.在我设计的类似系统中,有动作和效果。 These were base classes.这些是基类。 Each specific action (a machine gun attack, a specific spell, and so on) was a class derived from Action.每个特定动作(机枪攻击、特定法术等)都是从 Action 派生的 class。 Actions had an list of one or more specific effects that could be applied to Targets.动作有一个可以应用于目标的一个或多个特定效果的列表。 This was achieved using Dependency Injection.这是使用依赖注入实现的。

The combat engine didn't do all the math itself.战斗引擎本身并没有做所有的数学运算。 Essentially, it asked the Target to calculate its defense rating, then cycled through all the active Actions and asked them to determine if any of its Effects applied to the Target.本质上,它要求目标计算其防御等级,然后循环所有活动的动作并要求它们确定是否有任何效果适用于目标。 If they applied, it asked the Action to apply its relevant Effects to the Target.如果他们应用了,它会要求操作将其相关效果应用到目标。

Thus, the combat engine is small, and each Effect is very small, and easy to maintain.因此,战斗引擎很小,每个效果器都很小,易于维护。

If your system is one huge monolithic structure, you might consider a similar architecture.如果您的系统是一个巨大的单体结构,您可能会考虑使用类似的架构。

OnHit should be an event handler, for starters. OnHit 应该是一个事件处理程序,对于初学者。 Any object that is hit should raise a Hit event, and then you can have one or more event handlers associated with that event.任何被命中的 object 都应该引发一个 Hit 事件,然后您可以拥有一个或多个与该事件关联的事件处理程序。

If you cannot split up your current OnHit function into multiple event handlers, you can split it up into a single event handler but refactor it into multiple smaller methods that each perform a specific test or a specific calculation.如果您无法将当前的 OnHit function 拆分为多个事件处理程序,则可以将其拆分为单个事件处理程序,但将其重构为多个较小的方法,每个方法执行特定的测试或特定的计算。 It will make your code much more readable and maintainable.它将使您的代码更具可读性和可维护性。

IMHO Mike Hofer gives the leads.恕我直言,迈克霍弗给出了线索。

The real point is not whether it's a matter of an extension method or not.真正的问题不是它是否是扩展方法的问题。 The real point is that speaking of a single (extension or regular) method is unconceivable for such a complicated bunch of calculations.真正的问题是,对于如此复杂的一堆计算来说,谈论单一(扩展或常规)方法是不可想象的。

Before thinking about the best implementation, you obviously need to rethink the whole thing to identify the best possible dispatch of responsibilities on objects.在考虑最佳实现之前,您显然需要重新考虑整个事情,以确定对对象的最佳责任分派。 Each piece of elemental calculation must be done by the object it applies to.每一项元素计算都必须由其适用的 object 完成。 Always keep in mind the GRASP design patterns , especially Information Expert , Low Coupling and High Cohesion .始终牢记GRASP 设计模式,尤其是Information ExpertLow CouplingHigh Cohesion

In general, each method in your project should always be a few lines of code long, no more.一般来说,你项目中的每个方法都应该是几行代码,不多不少。 For each piece of calculation, think of which are all the classes on which this calculation is applicable.对于每一项计算,想想哪些是该计算适用的所有类。 Then make this calculation a method of the common base class of them.然后将此计算作为它们的公共基数 class 的方法。

If there is no common base class, create a new interface, and make all these classes implement this interface.如果没有公共基础 class,则创建一个新接口,并使所有这些类都实现该接口。 The interface might have methods or not: it can be used as a simple marker to identify the mentioned classes and make them have something in common.接口可能有方法也可能没有:它可以用作一个简单的标记来识别所提到的类并使它们具有共同点。

Then you can build an elemental extension method like in this fake example:然后你可以像这个假例子一样构建一个基本的扩展方法:

public interface IExploding { int ExplosionRadius { get; } }

public class Grenade : IExploding { public int ExplosionRadius { get { return 30; } } ... }

public class StinkBomb : IExploding { public int ExplosionRadius { get { return 10; } } ... }

public static class Extensions
{
    public static int Damages(this IExploding explosingObject)
    {
        return explosingObject.ExplosionRadius*100;
    }
}

This sample is totally cheesy but simply aims to give leads to re-engineer your system in a more abstracted and maintenable way.这个示例非常俗气,但只是旨在以更抽象和可维护的方式重新设计您的系统。

Hope this will help you !希望对你有帮助 !

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM