我目前正在努力实现一组文件系统类。如果我没有弄错的话,我想这需要复合模式。所以我设置了以下类:
抽象类Node
,其中包含对其父文件夹的引用以及实现Folder
的两个类File
和Node
。文件夹包含其所有子项的集合以及添加和删除子项的方法。
问题是,我无法弄清楚如何正确实施所有方法。在我看到的所有例子中,没有提到孩子的父母。 AddChild
方法如何确保正确设置子项的父引用?我通过检查child.Parent
是否已设置到文件夹或它是否抛出ArgumentException
来解决这个问题。 AddChild
也可能抛出像DuplicateNameException
之类的异常这一事实使事情变得更加复杂。所以我的方法现在看起来像这样:
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(...))
。
我的解决方案有效,但我不相信这是正确的方法。也许有人有更好的解决方案,或者可以指出一个很好的例子。提前谢谢。
编辑:下面的最小完整类定义。
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 :(得分:1)
如何以相反的方式做到这一点:
Folder.AddChild(Node child)
{
child.Parent = this;
this._children.Add(child); // or what ever your doing to store the children
...
}
答案 1 :(得分: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);
}
}
我只是自由职业者,但这是一个想法。我真的认为没有必要跟踪你的父母,我认为最终会变成一个相当麻烦的解决方案。
答案 2 :(得分:1)
当我实现双向关联时,我通常会将所有关联维护移动到其中一方。在这种情况下,我选择了文件夹。
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); }
}
}
答案 3 :(得分: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
{
}
孩子知道如何建立父母;父母知道如何收养孩子。