2012-03-28 3 views
4

現在、ファイルシステムクラスの実装には苦労しています。私は間違っていない場合、これは複合パターンを必要とすると思います。だから私は、次のクラスを設定します。C#の親参照を持つファイルとフォルダ構造の複合パターン

その親フォルダを参照すると、二つのクラスFolderNodeを実装Fileを持っている抽象クラスNodeを。フォルダには、すべての子のコレクションと子を追加および削除するメソッドが含まれています。

問題は、すべてのメソッドを正しく実装する方法がわかりません。私が見てきたすべての例では、子供の親に対する参照はありません。 AddChildメソッドは、どのようにして子の親参照が正しく設定されていることを確認できますか? child.Parentが既にフォルダに設定されているか、ArgumentExceptionがスローされているかどうかを確認して解決しました。この問題は、AddChildDuplicateNameExceptionなどの例外をスローする可能性があります。だから私の方法は、次のようになります。

File.AddTo(Folder folder) { 
    this.Parent = folder; 
    try { 
     folder.AddChild(this); 
    } catch { 
     this.Parent = null; 
     throw; 
    } 
} 

Folder.AddChild(Node child) 
{ 
    if(child.Parent != this) 
     throw new ArgumentException(...); 
    ... 
} 

は今、私はこの醜いAddTo方法を持っているとsomeFolder.AddChild(new File(...))ような何かを行うことはできません。私はそれが例えばListViewItemでどのように実装されたのだろうか。私はちょうどsomeListView.Items.Add(new ListViewItem(...))を行うことができます。

私のソリューションは機能しますが、これを行うのが正しい方法であるとは私は確信していません。たぶん誰かがより良い解決策を持っているか、私に良い例を教えてくれるかもしれません。前もって感謝します。

EDIT:下記の完全なクラスの定義。

abstract class Node 
{ 
    public Folder Parent { get; protected set; } 
    public string Name { get; private set; } 

    public Node(string name) { 
     Parent = null; 
     Name = name; 
    } 
} 

class Folder : Node { 
    private Dictionary<string, Node> _children; 

    public Folder(string name) : base(name) { 
     // Other initializations here... 
    } 

    public void AddChild(Node child) { 
     if(child is Folder) 
      ((Folder)child).Parent = this; // Damn, doesn't work for files!!! 
     else if(child.Parent != this) 
      throw new ArgumentException(); 

     if(_children.ContainsKey(child.Name)) 
      throw new DuplicateNameException(); 

     _children[child.Name] = child; 
    } 
} 

class File : Node { 
    public File(string name) : base(name) { 
     // Other initializations here... 
    } 

    public void AddTo(Folder folder) { 
     Parent = folder; 
     try { 
      folder.AddChild(this); 
     } catch { 
      Parent = null; 
     } 
    } 
} 
+0

現在、ファイル、フォルダ、ノードの定義はありますか? – KazR

答えて

0

AddChild()は親のメソッドです。

法の目的を考えると、子供で親への参照を維持するためにあなたの欲求、あなたはおそらくAddChild方法では、親によって設定することができ、子供のプロパティを公開する必要があります。

public abstract class Node 
{ 
    private Node parent; 

    internal void SetParent(Node parent) 
    { 
     this.parent = parent; 
    } 
} 

public class Folder : Node 
{ 
    void AddChild(Node child) 
    { 
     this.children.Add(child); 
     child.SetParent(this); // or, you could use a C# Property 
    } 
} 


public class File : Node 
{ 
} 

子供は親の確立方法を知っています。親は子供を養子にする方法を知っています。

+0

これは書かれているとおりに動作しません.Folder内のAddChildからchild.SetParentにアクセスすることはできません。 – KazR

+0

oops - 私は 'protected'を意味するわけではなく、' internal'を意味しました。私はそれを修正しました。 – Cheeso

1

どのようなことを別の方法をやっについて:

Folder.AddChild(Node child) 
{ 
    child.Parent = this; 
    this._children.Add(child); // or what ever your doing to store the children 
    ... 
} 
+0

これはまさに私が書こうとしていたものなので、なぜAddToメソッドが必要なのかわかりません! –

+1

これは 'Parent'が公にアクセス可能であることを必要とします。だから、だれでも 'someNode.Parent = nonsense' – user1047771

+0

を実行することができますが、質問に表現されているように、Parentはすでにノードのパブリックまたは保護されたメンバーですから、ファイルとフォルダの両方にアクセスできます。 – Jaime

1

あなたが親のメソッドを介して行われるべき親に子を追加する場合。親はそれ自身の状態を確認/検証し、その前提条件が満たされていることを確認できます。その親が有効であるかどうかを判断するのは、ノードまでではありません。親がそれを行うようにしてください。

ので、コードを経由して、あなたのようなものがあります:

public class Node 
{ 
    public string Name { get; set; } 
    public abstract void Add(Node child); 
    protected abstract void CreateOnDisk(); 
} 

public class File 
{ 
    public override void Add(Node child) 
    { 
     //No op, since you can't add a child to a file 
    } 

    protected override void CreateOnDisk() 
    { 
     File.Create(this.Name); 
    } 
} 

public class Directory 
{ 
    public override void Add(Node child) 
    { 
     child.Name = Path.Combine(this.Name, child.Name); 
     child.CreateOnDisk(); 
    } 

    protected override CreateOnDisk() 
    { 
     Directory.Create(this.Name); 
    } 
} 

を私はちょうど私の頭の上から少しフリーランス、それはアイデアを与えることです。私は本当にあなたの親を追跡する必要はないと思っています。そして、それはかなり厄介な解決策であることが最終的に分かると思います。

+0

Er、テストなしの問題/ VSは少し離れてしまうことです。このコンセプトを取って、Nameプロパティの使用をきれいにする必要があります(これは、パスと名前の2つのプロパティである必要があります)。 –

+0

私はアクセス制御の解決のために親参照を使用することを計画していました。つまり、ノードで操作が実行された場合、アクセス制御リストをチェックします。一致するものが見つからない場合は親のリストをチェックします。 ..親は 'folder1.Add(node);を避けるのにも役立ちます。 folder2.Add(node); '< - oops、もうツリーではない – user1047771

+0

なぜ" node "で表されるファイル/ディレクトリが各フォルダに追加されないのでしょうか? C:\ dir1とC:\ dir2に "temp.txt"を作成すると、2つの異なるテキストファイルがあります。シンボリックリンクではなく、テキストファイルです。 –

1

私は双方向アソシエーションを実装すると、通常、すべてのアソシエーションメンテナンスを一方のサイドに移動します。この場合、私はFolderを選択しました。

public abstract class Node 
{ 
    public Folder Parent { get; set; } 
    public string Name { get; set; } 
    public abstract long Size { get; } 
} 

public class File : Node 
{   
    private long _size; 

    public override long Size 
    { 
     get { return _size; } 
    } 

    public void AddTo(Folder folder) 
    { 
     folder.Add(this); 
    } 

    public void RemoveFrom(Folder folder) 
    { 
     folder.Remove(this); 
    } 
} 

public class Folder : Node 
{ 
    private List<Node> _children = new List<Node>(); 

    public void Add(Node node) 
    { 
     if (node.Parent == this) 
      return; // already a child of this folder 

     _children.Add(node); 
     node.Parent = this; 
    } 

    public void Remove(Node node) 
    { 
     if (node.Parent != this) 
      return; // not a child of this folder 

     _children.Remove(node); 
     node.Parent = null; 
    } 

    public override long Size 
    { 
     get { return _children.Sum(node => node.Size); } 
    } 
} 

PS双方向結合を排除しようとすると、頭痛が増えます。

UPDATE 単方向の関連付けを使用すると、Nodeクラスに醜いFolderフィールドがない単純なコードがあります(基本クラスがその子に依存する場合は嫌です)。また、ファイルを追加/削除する際の頭痛もありません。

public abstract class Node 
{ 
    public string Name { get; set; } 
    public abstract long Size { get; } 
} 

public class File : Node 
{   
    private long _size; 

    public override long Size 
    { 
     get { return _size; } 
    } 
} 

public class Folder : Node 
{ 
    private List<Node> _children = new List<Node>(); 

    public void Add(Node node) 
    { 
     if (_children.Contains(node)) 
      return; 

     _children.Add(node); 
    } 

    public void Remove(Node node) 
    { 
     if (!_children.Contains(node)) 
      return; 

     _children.Remove(node); 
    }   

    public override long Size 
    { 
     get { return _children.Sum(node => node.Size); } 
    } 
} 
関連する問題