C# 扩展大类以提高可读性

发布于 2024-11-09 20:31:38 字数 637 浏览 5 评论 0原文

我有一个大型抽象类来处理游戏中的武器。战斗循环通过一系列基本功能:

OnBeforeSwing
OnSwing
OnHit || OnMiss

我想到的是将所有与战斗伤害相关的计算移动到另一个处理该问题的文件夹中。与战斗伤害相关的计算。

我想知道将 OnHit 方法作为扩展方法来这样做是否正确,或者实现这一目标的最佳方法是什么。

还。 OnHit 代码的某些部分会定期进行修改,命中伤害公式很大,因为它考虑了很多条件,如抗性、变形法术、物品奖励、特殊属性和其他类似的游戏元素。

最后是 500 行的 OnHit 函数,这让我有点害怕。即使有区域指令,也很难在不迷失在迷宫中甚至分散自己注意力的情况下完成它。

如果我要使用此功能扩展武器,而不仅仅是 OnHit 功能,我可以尝试将攻击的不同部分分离到其他功能中。

话又说回来,也许我可以通过从武器类中的 OnHit 调用类似 CombatSystem.HandleWeaponHit 之类的东西来实现这一点,而不是使用扩展方法。可能更合适。

基本上我的问题是,像这样保留它是否确实是最好的解决方案,或者我是否可以(应该?)将这部分代码移动到扩展方法或处理损坏模型的单独帮助程序类中,以及我是否应该尝试并将函数拆分为更小的“任务”函数以提高可读性。

I have a large abstract class that handles weapons in my game. 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.

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.

This ends with a 500 line OnHit function, which kind of horrifies me. 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.

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. 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

爱要勇敢去追 2024-11-16 20:31:41

恕我直言,迈克·霍弗(Mike Hofer)领先。

真正的重点不在于是否是扩展方法的问题。真正的要点是,对于如此复杂的一堆计算来说,单一的(扩展或常规)方法是不可想象的。

在考虑最佳实现之前,您显然需要重新考虑整个事情,以确定对象上的最佳可能的职责分配。每一项基本计算都必须由它所适用的对象来完成。始终牢记GRASP设计模式,尤其是信息专家低耦合高内聚

一般来说,项目中的每个方法都应该只有几行代码,不能再长了。对于每一项计算,请考虑该计算适用的所有类。然后使这个计算成为它们的公共基类的方法。

如果没有公共基类,则创建一个新接口,并使所有这些类都实现该接口。该接口可能有方法,也可能没有:它可以用作一个简单的标记来识别所提到的类并使它们具有共同点。

然后,您可以构建一个基本的扩展方法,就像这个假示例一样:

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;
    }
}

这个示例完全是俗气的,但只是旨在提供线索,以更抽象和可维护的方式重新设计您的系统。

希望这会对您有所帮助!

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. Always keep in mind the GRASP design patterns, especially Information Expert, Low Coupling and High 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.

If there is no common base class, create a new interface, and make all these classes implement this interface. 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 !

属性 2024-11-16 20:31:40

我将冒险建议你的引擎可能不够抽象。请注意,除了您在OP中告诉我的内容之外,我在不了解有关您的系统的任何其他信息的情况下提出了这一建议。

在我设计的类似系统中,有动作和效果。这些是基类。每个特定动作(机枪攻击、特定咒语等)都是从 Action 派生的类。行动有一个可以应用于目标的一个或多个特定效果的列表。这是使用依赖注入实现的。

战斗引擎本身并没有完成所有的数学计算。本质上,它要求目标计算其防御等级,然后循环执行所有活动操作并要求它们确定其任何效果是否适用于目标。如果他们申请,它会要求操作将其相关效果应用于目标。

这样,战斗引擎就很小,每个Effect也很小,并且易于维护。

如果您的系统是一个巨大的整体结构,您可能会考虑类似的架构。

I'm going to go out on a limb and suggest that your engine may not be abstracted enough. Mind you, I'm suggesting this without knowing anything else about your system aside from what you've told me in the 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. 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.

裂开嘴轻声笑有多痛 2024-11-16 20:31:40

对于初学者来说,OnHit 应该是一个事件处理程序。任何被击中的对象都应该引发 Hit 事件,然后您可以拥有一个或多个与该事件关联的事件处理程序。

如果您无法将当前的 OnHit 函数拆分为多个事件处理程序,则可以将其拆分为单个事件处理程序,但将其重构为多个较小的方法,每个方法执行特定的测试或特定的计算。它将使您的代码更具可读性和可维护性。

OnHit should be an event handler, for starters. Any object that is hit should raise a Hit event, and then you can have one or more event handlers associated with that event.

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. It will make your code much more readable and maintainable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文