【问题标题】:Grouping Variables For Better Organization [closed]为更好的组织分组变量[关闭]
【发布时间】:2017-03-25 03:52:18
【问题描述】:

我的问题已经在这里被问过了:How to build a group of constant variables in c# 但我觉得好像问的不是同一件事。我会尽力解释,请听我说完。

假设您必须代表一个玩家的属性,例如力量、敏捷、耐力等。但同时您还想列出与同一组不直接相关的其他属性。除了主要属性之外,您还可以拥有概率属性,例如准确度、闪避和暴击。以及后勤属性,例如:运动、主动性和跳跃。自然,这些属性服务于不同的目的,因此,应该单独分组(或者至少在我看来他们应该)。我可以使用多个类来实现这一点:

namespace Example
{
    public class PrimaryAttributes
    {

        public int Strength { get; set; }
        public int Agility { get; set; }
        public int Stamina { get; set; }
        public int Intellect { get; set; }
        public int Willpower { get; set; }
        public int Spirit { get; set; }

        public PrimaryAttributes()
        {
            // Do stuff here
        }

        // Do more stuff here


    }
}

继续...

namespace Example
{
    public class ProbabilisticAttributes
    {

        public int Accuracy { get; set; }
        public int Evasion { get; set; }
        public int CriticalStrike { get; set; }

        public ProbabilisticAttributes()
        {
            // Do stuff here
        }

        // Do more stuff here


    }
}

继续...

namespace Example
{
    public class LogisticalAttributes
    {

        public int Movement { get; set; }
        public int Initiative { get; set; }
        public int Jump { get; set; }

        public LogisticalAttributes()
        {
            // Do stuff here
        }

        // Do more stuff here


    }
}

然后将它们全部托管在一个类中,如下所示:

namespace Example
{
    public class Statistics
    {

        public PrimaryAttributes PrimaryAttributes { get; set; }
        public ProbabilisticAttributes ProbabilisticAttributes { get; set; }
        public LogisticalAttributes LogisticalAttributes { get; set; }

        public LogisticalAttributes()
        {
            PrimaryAttributes = new PrimaryAttributes();
            ProbabilisticAttributes = new ProbabilisticAttributes();
            LogisticalAttributes = new LogisticalAttributes();
        }

        // Do more stuff here


    }
}

这将达到能够按照“stats.PrimaryAttributes.Strength”的方式调用某些东西的效果,它干净且有条理。但是,我宁愿不这样做。我想在同一个类中托管所有变量,而不必使用其他类。那么有什么问题呢?我仍然希望能够在扩展范围之后组织它们,或者我猜想什么可以称为命名空间;一种分隔线,如果你愿意的话。我认为在 C# 语言中不存在这样的东西......或任何语言。但我想知道我可以多接近复制这种行为。这是我正在寻找的示例(不是真正的 C#,只是一个示例)。

namespace Example
{
    public class Attributes
    {
        group PrimaryAttributes // Imaginary "group" keyword.
        {
            int Strength { get; set; }
            int Agility { get; set; }
            int Stamina { get; set; }
            int Intellect { get; set; }
            int Wisdom { get; set; }
            int Spirit { get; set; }
        }

        group ProbabilisticAttributes // Imaginary "group" keyword.
        {
            int Evasion { get; set; }
            int Accuracy { get; set; }
            int CriticalStrike { get; set; }
        }

        group LogisticalAttributes // Imaginary "group" keyword.
        {
            int Movement { get; set; }
            int Initiative { get; set; }
            int Jump { get; set; }
        }

        public Attributes()
        {
            // Don't have to declare or initialize anything.
        }

        public int ReturnSomethingAmazing()
        {
            return this.PrimaryAttributes.Strength * this.PrimaryAttributes.Agility; // Notice the group accessor usage.
        }

        // Do more stuff here


    }
}

我希望你能明白我现在在说什么。我希望能够“范围”变量,但不使用单独的类。我还冒昧地思考了如何在编译时对其进行解析。本质上,组范围只是内联,所以myClassInstance.PrimaryAttributes.Strength

,将被最小化为myClassInstance.Strength。范围实际上并不存在,它只是为了让程序员更好地促进组织,而不需要在运行时在内存中消耗更多的对象。

最后,我想总结两个问题。

使用当前的 C# 是否有可能?

您认为这是推荐给 Microsoft 的好建议吗? 对于 C# 编程语言的补充?

【问题讨论】:

  • 在类中使用区域不会成功吗?或者您可以使用部分类并为每个组使用不同的文件。
  • class 组织它们的方法没有任何问题。您可能更喜欢struct,对于他们作为财产袋的目的来说,它有点冗长。我认为您想多了,因为每个类别的 class 都提供了您所需要的。
  • @Andrew 但是不能通过区域名称访问区域。
  • @Krythic 是的,我明白,我不会关心少数属性的堆分配。如果它们成为您的应用程序性能的瓶颈,那么我会吃掉我的鞋子 :) 再说一次,我认为您将已经有既定模式的东西过度复杂化了。
  • @mariocatch 我不应该提到内存,因为它回避了我的整体观点。我只是想澄清一种可能的用法。我关心的是组织。关于记忆我不能给出两个****,我只是想要组织。

标签: c#


【解决方案1】:

对于这类问题,唯一可能的答案是表达一种观点。有时人们的想法不同,有时他们不会,所以请多多包涵。

OOP 有时会变得困难和令人困惑,但这是我思考的方式以及我会做的事情。另外,我知道您想在没有“单独的课程”的情况下这样做,而我的建议恰恰相反。但我相信使用单独的摘要来做这件事是你“找到原力,卢克”的地方。

首先,让我们创建一个枚举来简化分组(以及在我们将来访问属性时取消分组):

public enum AttributeCategory
{
    Primary,
    Probabilistic,
    Logistical
}

现在,属性的概念非常适合用于接口。让我们创建它并创建一个关联的抽象来减少和简化代码(是的,过度使用接口,但谁在乎 :D):

public interface IAttribute
{
    string AttributeName { get; }
    AttributeCategory Category { get; }
    int Value { get; }
}

public abstract class AttributeBase : IAttribute
{
    protected virtual string AttributeName { get; }
    protected virtual AttributeCategory Category { get; }
    protected virtual int Value { get; }
}

// Note: one might want to implement a generic type for value, something like AttributeBase<T> {... T Value { get; } }

现在让我们定义一些额外的摘要,稍后你就会明白为什么我更喜欢这样做:

public abstract class PrimaryAttribute : AttributeBase
{
    protected override sealed AttributeCategory Category { get; } = AttributeCategory.Primary;
}

public abstract class ProbabilisticAttribute : AttributeBase
{
    protected override sealed AttributeCategory Category { get; } = AttributeCategory.Probabilistic;
}

public abstract class LogisticalAttribute : AttributeBase
{
    protected override sealed AttributeCategory Category { get; } = AttributeCategory.Logistical;
}

好的,现在我们可以实现实际的属性了:

public sealed class Strength : PrimaryAttribute
{
    protected override string AttributeName => "Strength";
}

public sealed class Stamina : PrimaryAttribute
{
    protected override string AttributeName => "Stamina";
}

public sealed class Accuracy : ProbabilisticAttribute
{
    protected override string AttributeName => "Accuracy";
}

public sealed class Initiative : LogisticalAttribute
{
    protected override string AttributeName => "Initiative";
}

有了我上面描述的“混乱”,我们现在可以创建一个描述这些属性集合的类:

public abstract class AttributeCollectionBase
{
    protected virtual List<IAttribute> Attributes { get; } = new List<IAttribute>();
    protected virtual IEnumerable<IAttribute> Get(AttributeCategory category)
    {
        return Attributes.Where(a => a.Category == category);
    }

    protected AttributeCollectionBase()
    {
        // Yup, we'll need this one place with the constructor that lists the "default" attributes... Might be for the best, though.
        Attributes.Add(new Strength());
        Attributes.Add(new Stamina());
        Attributes.Add(new Accuracy());
        Attributes.Add(new Initiative());
    }
}

最后,我们可以创建这个属性集合的实现:

public sealed class AttributeCollection : AttributeCollectionBase
{
    //... We don't need anything here to start. Maybe add something specific.
}

public class SomeCharacter
{
    //...
    public AttributeCollection Attributes { get; }
}

var someCharacter = new SomeCharacter();

现在,为什么要经历所有这些痛苦?好吧,现在如果需要为概率属性(一些通用计算)实现任何东西 - 需要在抽象类中进行一次修改(新的虚拟方法)。所有属性都需要更改吗?一段代码要调整 - AttributeBase。曾经需要分隔一些默认属性(假设是不同类别的字符)——只需要另一个AttributeCollectionBase 实现,例如KnightAttributeCollection。最后,您可以像这样实现“按类型获取属性”实现:

someCharacter.Attributes.Get(AttributeCategory.Logistical);

尽管如此,这是我个人分享的方式,它可能看起来/不是最理想的或难以理解的,这仅意味着“它总是取决于 ”。

【讨论】:

  • 这很有趣,但我想知道对于像具有某些属性的类这样简单的东西来说,这是否有点过度架构。你最终每个属性都有一个类(加上所有支持的类)!请记住,OP(Krythic)要求“无需使用其他类”。 :D 另外,如果其中一个不是int 类型怎么办?最后,由于接口成员在您的类中不公开,该代码不会给您带来错误吗?至少这不会在我的本地编译。
  • @Andrew,如果其中一个不是 int - 我已经在其中一个代码 cmets 中解决了这个问题,请引用:“// 注意:可能想要为值实现一个泛型类型,某事像 AttributeBase {... T Value { get; } }"。我实际上没有尝试过代码,你是对的,那些应该是公开的。最后,过度架构——也许,我什至会说也许。但就像在软件中一样——一切都在过度架构,直到它不是。处理架构过度的后果比架构不足的后果要容易得多。
【解决方案2】:

这是我刚刚想出的一种方法,不确定是否值得,但您可能会喜欢:

public class Attributes
{
    // PrimaryAttributes
    public class PrimaryAttr
    {
        public int Strength { get; set; }
        public int Agility { get; set; }
        public int Stamina { get; set; }
        public int Intellect { get; set; }
        public int Wisdom { get; set; }
        public int Spirit { get; set; }
    }

    private PrimaryAttr _primaryAttr;
    public PrimaryAttr PrimaryAttributes
    {
        get
        {
            if (this._primaryAttr == null)
                this._primaryAttr = new PrimaryAttr();

            return this._primaryAttr;
        }
    }


    // ProbabilisticAttributes
    public class ProbabilisticAttr
    {
        public int Evasion { get; set; }
        public int Accuracy { get; set; }
        public int CriticalStrike { get; set; }
    }

    private ProbabilisticAttr _probabilisticAttr;
    public ProbabilisticAttr ProbabilisticAttributes
    {
        get
        {
            if (this._probabilisticAttr == null)
                this._probabilisticAttr = new ProbabilisticAttr();

            return this._probabilisticAttr;
        }
    }


    // LogisticalAttributes
    public class LogisticalAttr
    {
        public int Movement { get; set; }
        public int Initiative { get; set; }
        public int Jump { get; set; }
    }

    private LogisticalAttr _logisticalAttr;
    public LogisticalAttr LogisticalAttributes
    {
        get
        {
            if (this._logisticalAttr == null)
                this._logisticalAttr = new LogisticalAttr();

            return this._logisticalAttr;
        }
    }


    // Rest of the implementation    
    public Attributes()
    {
        // Don't have to declare or initialize anything.
    }

    public int ReturnSomethingAmazing()
    {
        return this.PrimaryAttributes.Strength * this.PrimaryAttributes.Agility; // Notice the group accessor usage.
    }

    // Do more stuff here


}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-24
  • 1970-01-01
  • 1970-01-01
  • 2018-04-09
  • 2012-02-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多