2

私は初めて Robert Martin の SOLID 設計原則に固執しようとしていますが、それが苦手です。

本質的に、「ノード」オブジェクトの階層が必要です。一部のノードは NodeHosts、一部は NodeChildren、一部は Both です。誰もがこれを以前に行ったことがありますが、設計を過度に複雑にしたり、ノードのサブタイプで次のようなことをしたりせずに、SOLID で行う方法がわかりません。

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

これはリスコフの置換原理に違反していますよね?より良い方法は何ですか?これが私が今持っているものです。 代替テキスト

4

1 に答える 1

4

この答えは本当に大きくなりましたが、楽しかったです。どうぞ :)

かなり複雑な設計であることに同意します。インターフェイスは、「変化するものを抽象化する」ために使用する場合に役立ちますが、その例ではすべてが抽象化されています。これは例を追うのが非常に難しいため、何かが間違っていることを示す大きな指標となるはずです。スパゲッティ コードの反対はラザニア コード (多くの層) であり、それがまさにこの図です。

私が見る限り、あなたには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の場合、ノードのタイプは異なりますが、両方ともタイプがあります。これは、別の抽象化の資格があるとは思いません。タイプをベースノードに移動しました。

//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 に答える