【问题标题】:How can I have private data associated with public array members?如何拥有与公共数组成员关联的私有数据?
【发布时间】:2014-02-09 16:49:05
【问题描述】:

我正在用 C# 开发一个游戏,但我对正确的面向对象设计有点困惑。

游戏中有3D空间中的节点:

public class Node {
    public Vector3 Position;
    public Vector3 Size; // etc
}

然后,存在具有节点数组的路径。一个节点可以属于多个路径。路径具有与其每个节点相关联的一些数据(“元数据”)。问题是,路径的节点应该对其他类可访问,但相关的元数据应该保持隐藏

对于节点和元数据具有不同访问修饰符的两个数组需要工作以保持它们同步。

将节点与元数据配对的公共包装器类型也不是最佳解决方案 - 包装器类型仅对路径有意义,因此不应该是公共的。

将私有数据关联到公共数组成员的更好方法是什么?

【问题讨论】:

    标签: c# oop access-modifiers


    【解决方案1】:

    这个想法来自 nmclean 的回答和 cmets :)

    嵌套包装类确实是一个很好的解决方案。我使用了一种方法来提供对节点的公共访问。

    public class Path {
    
        // wraps a node and its metadata
        private class NodeData {
            // public members visible only to parent class
            public Node Node;
            public float SomeMetadata;
        }
    
        // private array...
        private NodeData[] nodeData;
    
        // ...public method
        public Node GetNode(int index) {
            return nodeData[index].Node;
        }
    }
    

    【讨论】:

      【解决方案2】:

      如果我理解正确(我只发布基本结构)。

      public class Node {
          public Vector3 position;
      }
      
      public class Path {
        private Dictionary<Node, Vector3> cameraPositions = new Dictionary<node,Vector3>();
        public List<Node> NodesInPath {get;}
      
        public Node AddNode(Node node, Vector3 cameraPosition);
        public Vector3 GetCameraPosition(Node node);
      }
      

      基本上,相机位置属于您的 Path 类(私下),当您将其添加到路径时,您可以为每个节点单独设置它。对于给定节点,每条路径都有一组不同的相机位置。

      【讨论】:

      • NodeInPath 在这里指的是什么?字典的问题是它没有排序,在这种情况下节点的顺序很重要。
      • 对不起,我的错...复制和粘贴您的代码。你的路径只是一个节点列表,使用任何你喜欢的(链表、标准列表、IEnumberable、SortedList)
      【解决方案3】:

      我可能会误解,但是只有两个集合有什么问题?

      public class Path {
          private NodeInPath[] nodesInPath;
          public Node[] nodes;
      }
      

      虽然不是将节点与元数据一起包装在 NodeInPath 之类的类中,但在节点与其元数据之间建立映射可能会更有用:

      public class NodeMetadata {
          public Vector3 cameraPosition;
      }
      
      public class Path {
          private Dictionary<Node, NodeMetadata> _nodeMetadataMapping;
          public Node[] nodes;
      }
      

      顺便说一下,数组不应该是公共字段。您允许项目在外部进行更改,但无法响应更改。除非每次访问节点时都重建此映射,否则它无法适应节点集合中的更改。见this post

      【讨论】:

      • 哦,NodeMetadata 类仍然是公开的,尽管它仅在路径的上下文中相关甚至有意义。所以这个解决方案仍然没有按照我希望的方式封装。
      • @ijukus 在这种情况下,它可以是Path 下的私人nested type
      【解决方案4】:

      你必须返回一个接口 INode 而不是具体的类。在接口上,您只定义允许在路径外访问的方法和属性。 Path 本身在内部使用具体的类节点,但只返回接口 INode。您的代码可能如下所示:

      public interface INode  {void SomeAccessableMethod(); }
      internal  class Vector3  {}
      
      internal class Node : INode
      {
        public void SomeAccessableMethod() {}
        public Vector3[] CameraPositions { get; set; }
      }
      
      public class Path
      {
       private readonly IList<INode> _nodesInPath = new List<INode>();
      
       public Path()
       {
         //Initalise all the nodes
         for(int cnt = 0; cnt < 10; cnt++)
         {
           var node = new Node();
           node.CameraPositions = new Vector3[1];
           node.CameraPositions[0] = new Vector3();
           _nodesInPath.Add(new Node());
         }
       }
       public INode[] NodesInPath
       {
         get { return _nodesInPath.ToArray(); }
       }
      }
      

      (我更喜欢使用列表而不是数组,并且初始化也取决于您。您也可以在路径类中定义 Node 类。这样它就不能在同一个程序集中访问)

      【讨论】:

      • 一个节点可以在多个路径中,并且对于每个路径中的每个节点都有一个摄像头位置。所以它是路径的属性(实际上是节点路径连接)而不是节点。
      • 对不起,但我认为当有人获取路径中的节点列表时,您希望相机位置类 (Vector3) 无法通过节点类访问 正确与否?如果这是正确的,那么节点的创建可以在一个单独的类(可能是工厂)中完成,然后添加到它们所属的不同路径中。如果您愿意,我可以添加执行此操作的代码
      猜你喜欢
      • 1970-01-01
      • 2012-10-25
      • 1970-01-01
      • 2014-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多