我想创建一个紧密遵循以下结构的层次结构:
(1)INodeBase - 包含一个Children属性,它是一个自身的集合(INodeBase)
(2)INodeFolder - 派生自INodeBase。
(3)NodeFolder - 实现INodeFolder。 Children属性的实现应该允许它包含INodeFolder类型和INodeItem类型的项目。
(4)INodeItem - 从INodeBase派生。
(5)NodeItem - 实现INodeItem。 Children属性的实现应该允许它包含NodeResult类型的项目。
(6)INodeResult - 派生自INodeBase。
(7)NodeResult - 实现INodeResult - 我不需要/想要这个类中的子属性,但是,如果可以正确地构造整体层次结构,我愿意在类中挂起一个空集合。 / p>
本质上,我想要节点的一种基本类型 - 并且假设节点可以包含其他节点。我认为泛型是要走的路 - 但问题是,如果我查询整个层次集合,或者更确切地说,如果我过滤它,当我递归遍历每个孩子的子集合(即展平我的我想知道什么是什么 - 也就是说,如果我在一个文件夹的Children集合中,我想知道什么时候我点击了FolderNode并且当我点击一个ItemNode时,然后当我通过Children属性一个ItemNode,我想知道我只是处理NodeResult类型。
那么,上述最佳方法是什么?
克里斯
答案 0 :(得分:1)
Altought,不是主要答案,为什么不直接使用类和对象而不是接口来设计对象层次结构。稍后您可以将其转换为界面层次结构。
enum NodeTypes { Unknown, Folder, File };
public abstract class CNodeBase {
protected List<CNodeBase> FItems;
public List<CNodeBase> Items();
public virtual NodeTypes NodeType() {
return NodeTypes.Unknown;
}
}
public class CNodeFolder: CNodeBase {
// ...
public override NodeTypes NodeType() {
return NodeTypes.Folder;
}
}
public class CNodeFile: CNodeBase {
// ...
public override NodeTypes NodeType() {
return NodeTypes.File;
}
}
public class CDemo {
void main () {
// root node is ALWAYS A folder
CNodeFolder RootNode = new CNodeFolder("\\");
CNodeBase AnyNode = null;
AnyNode = new CNodeFolder("c:");
RootNode.Add(AnyNode);
AnyNode = new CNodeFolder("d:");
RootNode.Add(AnyNode);
AnyNode = new CNodeFile("readme.txt");
RootNode.Add(AnyNode);
}
}
超类(抽象或具体)的工作方式与接口非常相似,但其优点是可以从中实例化对象,看看代码是否正常工作。
在我看来,你正试图做一些非常概念性的事情。也许如果你退后一步,去可以实例化的课程,你可以更实际地看到你的想法。
接口是一个非常好的功能,但起初很难理解。有时候,“退后一步,前进五步”是一个好主意。
答案 1 :(得分:1)
我认为以下代码都遵循您想要的规则,尤其是所有节点实施INodeBase
以及NodeResult
没有Children
集合的奖励。
以下是所需的接口:
public interface INodeBase
{
}
public interface INodeContainer : INodeBase
{
}
public interface INodeContainer<C> : INodeContainer
where C : INodeBase
{
IList<C> Children { get; }
}
public interface INodeFolder : INodeContainer<INodeContainer>
{
}
public interface INodeItem : INodeContainer<INodeResult>
{
}
public interface INodeResult : INodeBase
{
}
我添加了几个INodeContainer
接口 - 一个非通用接口和一个接口另一种通用。
以下是类定义:
public abstract class NodeBase : INodeBase
{
}
public abstract class NodeBase : INodeBase
{
}
public abstract class NodeContainer : NodeBase, INodeContainer
{
}
public abstract class NodeContainer<C> : NodeContainer, INodeContainer<C>
where C : INodeBase
{
public NodeContainer() { this.Children = new List<C>(); }
public IList<C> Children { get; private set; }
}
public class NodeFolder : NodeContainer<INodeContainer>, INodeFolder
{
}
public class NodeItem : NodeContainer<INodeResult>, INodeItem
{
}
public class NodeResult : INodeResult
{
}
现在你可以使用这样的代码:
var nf = new NodeFolder();
nf.Children.Add(new NodeFolder()); // Add `INodeFolder`
var ni = new NodeItem();
nf.Children.Add(ni); // or add `INodeFolder`, but nothing else.
var nr = new NodeResult();
ni.Children.Add(nr); // Only add `INodeResult`.
// nr does not have "Children" collection.
如果您愿意,可以在具体类型而不是接口上限制INodeContainer<C>
。这取决于您是想通过接口还是具体类来引用对象。
请告诉我这是否适合您。
答案 2 :(得分:0)
为什么需要让文件夹和项目实现相同的界面?
在我看来,这样一个更简单的结构会更好......
public class Folder
{
public List<Folder> Folders { get; }
public List<Item> Items { get; }
}
public class Item
{
public List<Result> Results { get; }
}
public class Result
{
}