【问题标题】:Null Object Pattern in a self-referencing type自引用类型中的空对象模式
【发布时间】:2021-11-27 15:06:02
【问题描述】:

假设我有一个名为Node 的类,它表示层次结构中的一个节点。 例如,它可能看起来像这样:

public class Node
{
  public readonly string Data { get; set; }
  public readonly Node Parent { get; set; }
  public readonly List<Node> Children { get; } = new()

  public Nome(string Data, Node parent)
  {
    Data = data;
    Parent = parent;
  }
}

请注意属性Parent 的类型为Node,并且它不可为空,因此我无法将null 分配给它。 现在假设我想为这个类实现Null Object Pattern,例如创建根节点。

我发现自己处于先有鸡还是先有蛋的境地,因为我无法在没有节点的情况下创建 Node

除了使Parent 可以为空之外,还有其他选择吗?

【问题讨论】:

  • 我个人认为“空对象模式”是一种反模式,原因不胜枚举。相反,我建议使用自定义联合类型。
  • 其实为什么不Parent属性标记为Node? Parent? (即将其标记为可空)。毕竟,当节点为根时,它可以有效地为null - 并添加一个简短的注释:“当Node 是图的根时,此属性为null”) .
  • 另外,问题标题是“自引用对象”,但我实际上并没有在这里看到任何自引用代码......请澄清。
  • @Dai 你是对的,感谢你的反馈。我更改了问题标题,希望它更清楚。
  • 现在它说“自引用对象” - 但您的代码中仍然存在零自引用。

标签: c# design-patterns


【解决方案1】:

如果你只使用一个类,你需要 nulltype 但你可以使用一个接口作为开始:

    public class Node : NodeRoot {
        public string Data { get; init; }
        public Node? Parent { get; init; }
        public List<Node> Children { get; init; } = new();

        private Node(string data) {
            Data = data;
        }

        private Node(string data, Node parent) {
            Data = data;
            Parent = parent;
        }

        public static Node Factory(string data, Node parent) => new(data, parent);

        public static INodeRoot Factory(string data) => new Node(data);
    }

    public interface INodeRoot {
        public string Data { get; }
        public List<Node> Children { get; }
    }

【讨论】:

  • 在 .NET 中,接口名称应以 I 开头 - 形容词应在名词之前,因此应命名为 public interface IRootNode
  • OP 的Node 类型是可变的,所以属性设置器应该是set,而不是init
  • 为什么会有静态工厂方法?它们不添加任何值,因此只需公开两个构造函数。
【解决方案2】:

您可以使用语法= null! 保持字段不可为空但强制为空(注意!,它告诉编译器信任您)。 我可能会将这种技术与用作根父级的子类和/或静态实例结合起来,并防止在访问该空父字段时出现问题(或添加计算字段isRoot)。

【讨论】:

  • 使用= null!仍然违反了默示合同,以及最小惊讶原则。如果具有引用类型的 C# 8.0+ 类属性具有 [NotNull] 属性(它由编译器添加),那么作为消费者 我会相信它,你所提议的反对。
  • 这就是为什么我建议将它隐藏在一个专用的子类中,这将保护该类的用户,从而尊重合同(从公共角度来看)。
  • 是的,但这是一个替代建议。我是说您最初的建议是 bad 建议(但子类化很好)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-23
  • 2020-01-24
  • 1970-01-01
  • 2016-10-31
相关资源
最近更新 更多