Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何最好地设计可伸缩类?_C#_Architecture_Class Design - Fatal编程技术网

C# 如何最好地设计可伸缩类?

C# 如何最好地设计可伸缩类?,c#,architecture,class-design,C#,Architecture,Class Design,我的意思是: 我现在基本上有一个类,它有太多的属性和函数。为了保持性能和可理解性,它需要以某种方式缩小。但我仍然需要所有这些属性和方法。 现在是这样的: class Apple float seedCount; ... ...about 25 variables and properties here. void Update() <-- a huge method that checks for each property and updates if so 因此产生

我的意思是: 我现在基本上有一个类,它有太多的属性和函数。为了保持性能和可理解性,它需要以某种方式缩小。但我仍然需要所有这些属性和方法。 现在是这样的:

class Apple

  float seedCount;
  ...
  ...about 25 variables and properties here.
  void Update() <-- a huge method that checks for each property and updates if so
因此产生了许多问题: 我必须经常检查每一个物体和每一帧的特征。如果种子没有初始化,我不必为它计算任何东西。如果是的话,我必须这么做。 如果我决定在Seed类中放入多个属性/特性,我还需要检查其中的每一个。 事情变得越来越复杂了。因此,我的问题是,我需要对所有特性进行粒度控制,无法将它们智能地划分为更大的子类。任何形式的子类都只包含一组需要检查和更新的属性。 我不能准确地创建Apple的子类,因为需要这样高粒度的控件。创建尽可能多的属性组合的类是疯狂的。 我的主要目标是:我想要简短的代码

我的主要目标是:我想要简短的代码

选项:

  • 将所有函数重写为静态函数,并为每个函数创建一个类
  • 用Perl重写代码库
  • 删除所有评论
  • 创建尽可能多的属性组合的类是疯狂的

    听起来您可能正在寻找一种新的方法,它的目的是使管理对象变得更容易,这些对象可以有许多不同的属性组合,而不需要指数级增长的继承权。对于每个属性或行为,您只需要一个小的子类(不一定是一个C#属性,只是可以组合在一起的东西),然后可以在运行时将它们组合在一起

    在您的情况下,每个Apple decorator类都将覆盖您的
    Update
    方法,并对其各个部分进行必要的计算,然后调用
    base.Update
    将其传递给下一行


    您的最终答案将在很大程度上取决于您的“苹果”到底是什么。

    您可以在Apple类中使用嵌套类

    我认为这里的关键是你要把所有的东西都放在一节课上。因此,类必须不断地检查它有什么和没有什么。解决方案是创建子类或装饰器,这些子类或装饰器已经知道它们是否有特定的东西。这样他们就不必每次都检查了


    因为你有这么多的属性,它们可能以不同的方式组合在一起,所以听起来装饰解决方案更适合你。

    我认为你走的是正确的道路:组合。您可以将您的类与所需的其他类组合在一起。但你也需要相应地委派责任。在您的示例中,应该由
    Seed
    类负责检查其内部状态,而
    Apple
    只是委托给它


    至于可选特性问题,也许您可以使用而不是空引用。这样,您就不必每次都检查
    null
    ,代码就更加一致了。

    如果您的方法应该是空的,那么您的方法可能不是空的

    如果将Seed类与Apple类分开,为什么不将使用Seed信息的方法也移动到Seed类中呢

    如果这些方法需要有关其他Apple属性的信息,您可以将其作为参数传递

    通过这样做,我想您可以消除初始化检查

    这是一本关于如何解决此类问题的好书:


    这个问题我已经思考了一段时间,我想出了另一个解决方案。这可能有点离经叛道和反面向对象,但如果你还不灰心,请继续阅读

    以Apple示例为基础:Apple类可以包含许多属性,这些属性可以归类为相关组。例如,我使用了一个Apple类,该类的一些属性与苹果的种子有关,而其他属性与苹果的皮肤有关

  • 苹果
    A.种子
    a1。GetSeedCount
    a2
    B皮肤
    b1。GetSkinColor
    b2 我正在使用dictionary对象存储所有Apple属性

    我编写了扩展方法来定义属性的访问器,使用不同的类将它们分开并组织起来

    通过对属性使用字典,您可以在任何时候迭代存储在thusfar中的所有属性(如果您必须检查所有属性,因为这听起来像是您在更新方法中需要的)。不幸的是,您丢失了数据的强类型(至少在我的示例中是这样,因为我使用的是字典。您可以为所需的每种类型使用单独的字典,但这需要更多的管道代码来将属性访问路由到正确的字典

    通过使用扩展方法定义属性的访问器,您可以将每个逻辑属性类别的代码分开。这样可以将内容组织到独立的相关逻辑块中

    下面是我提出的一个示例,用于测试这将如何工作,并给出了一个标准警告,即如果您继续沿着这条路径走下去,健壮性将是有序的(验证、错误处理等)

    Apple.cs

    namespace ConsoleApplication1
    {
        using System.Collections.Generic;
        using System.Text;
    
        public class Apple
        {
            // Define the set of valid properties for all apple objects.
            private static HashSet<string> AllowedProperties = new HashSet<string>(
                new string [] {
                    "Color",
                    "SeedCount"
                });
    
            // The main store for all properties
            private Dictionary<string, string> Properties = new Dictionary<string, string>();
    
            // Indexer for accessing properties
            // Access via the indexer should be restricted to the extension methods!
            // Unfortunately can't enforce this by making it private because then extension methods wouldn't be able to use it as they are now.
            public string this[string prop]
            {
                get
                {
                    if (!AllowedProperties.Contains(prop))
                    {
                        // throw exception
                    }
    
                    if (Properties.ContainsKey(prop))
                    {
                        return this.Properties[prop];
                    }
                    else
                    {
                        // TODO throw 'property unitialized' exeception || lookup & return default value for this property || etc.
    
                        // this return is here just to make the sample runable
                        return "0"; 
                    }
                }
    
                set
                {
                    if (!AllowedProperties.Contains(prop))
                    {
                        // TODO throw 'invalid property' exception
    
                        // these assignments are here just to make the sample runable
                        prop = "INVALID";
                        value = "0";
                    }
    
                    this.Properties[prop] = value.ToString();
                }
            }
    
            public override string ToString()
            {
                StringBuilder sb = new StringBuilder();
    
                foreach (var kv in this.Properties)
                {
                    sb.AppendFormat("{0}={1}\n", kv.Key, kv.Value);
                }
    
                return sb.ToString();
            }
        }
    }
    
    这是一次试驾:

    Program.cs

    namespace AppleExtensionMethods
    {
        using System;
        using ConsoleApplication1;
    
       // Accessors for Seed Properties
        public static class Seed
        {
            public static float GetSeedCount(this Apple apple)
            {
                return Convert.ToSingle(apple["SeedCount"]);
            }
    
            public static void SetSeedCount(this Apple apple, string count)
            {
                apple["SeedCount"] = count;
            }
        }
    
       // Accessors for Skin Properties
        public static class Skin
        {
            public static string GetSkinColor(this Apple apple)
            {
                return apple["Color"];
            }
    
            public static void SetSkinColor(this Apple apple, string color)
            {
                apple["Color"] = ValidSkinColorOrDefault(apple, color);
            }
    
            private static string ValidSkinColorOrDefault(this Apple apple, string color)
            {
                switch (color.ToLower())
                {
                    case "red":
                        return color;
    
                    case "green":
                        return color;
    
                    default:
                        return "rotten brown";
                }
            }
        }
    }
    
    namespace ConsoleApplication1
    {
        using System;
        using AppleExtensionMethods;
    
        class Program
        {
            static void Main(string[] args)
            {
                Apple apple = new Apple();
    
                apple.SetSkinColor("Red");
                apple.SetSeedCount("8");
    
                Console.WriteLine("My apple is {0} and has {1} seed(s)\r\n", apple.GetSkinColor(), apple.GetSeedCount());
    
                apple.SetSkinColor("green");
                apple.SetSeedCount("4");
    
                Console.WriteLine("Now my apple is {0} and has {1} seed(s)\r\n", apple.GetSkinColor(), apple.GetSeedCount());
    
                apple.SetSkinColor("blue");
                apple.SetSeedCount("0");
    
                Console.WriteLine("Now my apple is {0} and has {1} seed(s)\r\n", apple.GetSkinColor(), apple.GetSeedCount());
    
                apple.SetSkinColor("yellow");
                apple.SetSeedCount("15");
    
                Console.WriteLine(apple.ToString());
    
                // Unfortunatly there is nothing stopping users of the class from doing something like that shown below.
                // This would be bad because it bypasses any behavior that you have defined in the get/set functions defined
                // as extension methods.
                // One thing in your favor here is it is inconvenient for user of the class to find the valid property names as
                // they'd have to go look at the apple class. It's much easier (from a lazy programmer standpoint) to use the
                // extension methods as they show up in intellisense :) However, relying on lazy programming does not a contract make.
                // There would have to be an agreed upon contract at the user of the class level that states, 
                //  "I will never use the indexer and always use the extension methods!"
                apple["Color"] = "don't panic";
                apple["SeedCount"] = "on second thought...";
    
                Console.WriteLine(apple.ToString());
            }
        }
    }
    
    在11月7日(日期,而不是商店)发表评论:)
    在您提供的示例代码中,有一条注释说明:

    “如你所见,我不能打电话 关于“怪物”的其他基本方法

    你意识到你可以在这一点上做类似的事情:

    BasicBroodmother bm = monster as BasicBroodmother;
    if (bm != null)
    {
        bm.Eat();
    }
    
    您的代码没有太多内容(我知道这只是一个示例),但当我看到它时,我觉得您应该能够改进设计
    BasicBroodmother bm = monster as BasicBroodmother;
    if (bm != null)
    {
        bm.Eat();
    }