2

我第一次尝试坚持 Robert Martin 的 SOLID 设计原则,但我并不擅长。

本质上,我需要一个“节点”对象的层次结构。有些节点是 NodeHost,有些是 NodeChildren,有些是 Both。每个人以前都做过这个,但我不知道如何在不使设计过于复杂或在节点子类型中做类似事情的情况下做到这一点:

 INodeHostType node;
 public INodeType NodeType
 {
 ....
      set 
      {
          node = (INodeHostType)value;
      }
 }

这违反了里氏替换原则对吧?有什么更好的方法?这就是我现在所拥有的。 替代文字

4

1 回答 1

4

伙计,这个答案确实增长了,但很有趣。开始了 :)

我同意这是一个相当复杂的设计。当您使用接口来“抽象变化的内容”时,接口很有帮助,但在该示例中,所有内容都是抽象的。这个例子真的很难理解,所以这应该是一个很大的指标,表明有问题。Spaghetti Code 的对立面是 Lasagna Code(多层),这正是这张图的内容。

从我可以看到你有3组。

  • 节点(子、父等)
  • 节点类型
  • 使成为

让我们从 Nodes 开始,SOLID 确实告诉您对接口进行编码,但这并不一定意味着它必须是一个实际的接口。将常规的旧继承与扩展基节点的子节点一起使用是完全可以接受的。在这种情况下,这仍然是可靠的并且是有意义的。

public class Node
{

    public var NodeType { get; set; }
    public var DisplayText { get; set; }
    public IRenderable Renderer { get; set; }

    public Node()
    {
        // TODO: Add constructor logic here
    }

    public void Render()
    {
        Renderer.Render();
    }
}

public class ChildNode : Node
{
    public var Owner {get; set;}
    public var Sequence {get; set;}

    public ChildNode()
    {
        NodeType = "Child"; //use an enum
        DisplayText = "nom nom nom babies";
        Renderer = new ChildRenderer();
    }
}

//Parent Node is more of the same

对于 Node Type,确实节点具有不同的类型,但它们仍然具有类型。我认为这不符合单独抽象的条件。我刚刚将 type 移到你的 basenode 中。

//This didn't add value so its just an enum used in the baseclass now

对于 Render,现在你正在做一些事情。由于 ChildNodes 和 ParentNodes 的呈现方式不同,因此将其抽象是有意义的。虽然,我看到 IRenderer 中的所有属性都在 IRenderContext 中重复,所以我只是将它们折叠成 1。

interface IRenderable
{
    //properties
    // TODO: Add properties here

    //methods
    void Render();
}

interface ChildRenderer : IRenderable
{
    void Render()
    {
        //Render Me Here
    }
}

//ParentRender() is more of the same

//I could add all sorts of functionallity with out touching other code
//     ManChildRenderer(), TripletsChildRenderer()

类图看起来像这样 。坚实的例子

好的,这一切都很好,但是为什么所有额外的工作都需要。让我们看看最终的实现。

public static void main()
{
    //if this isnt acceptle instantiation use a NodeFactory
    Node node1 = new ParentNode();
    Node node2 = new ChildNode();

    //Now we don't care about type -- Liskov Substitution Principle
    node1.Render();
    node2.Render();

    //adding or changing functionality is now non-breaking
    node1.Renderer = new ManChildRender();
    //I've added a whole new way to render confident I didnt break the old renders
    //In fact I didn't even upon those class files
}
于 2011-03-18T23:53:25.380 回答