为复合模式的叶节点实现 IEnumerable
Implementing IEnumerable for Leaf Nodes of Composite Pattern
我已经实现了如下的复合模式
public interface IComponent
{
string Name { get; }
}
public interface IComposite : IComponent
{
void AddRange(IEnumerable<IComponent> components);
}
public interface ILeaf : IComponent
{
string Content { get; }
string Parent { get; }
}
public class Composite : IComposite
{
// return an iterator?
private readonly List<IComponent> _children = new List<IComponent>();
public Composite(string name)
{
Name = name;
}
public string Name { get; }
public void AddRange(IEnumerable<IComponent> components)
{
_children.AddRange(components);
}
}
public class Leaf : ILeaf
{
public string Name { get; }
public string Content { get; }
public string Parent { get; }
public Leaf(string name, string content, string parent)
{
Name = name;
Content = content;
Parent = parent;
}
}
我从 xml 文件中填充了如下复合材料
var collection = XElement.Load(@"C:\somexml.xml");
var composite = CreateComposite(collection);
哪里
public IComponent CreateComposite(XElement element)
{
if (!element.HasElements)
return new Leaf(element.Name.LocalName, element.Value, element.Parent.Name.LocalName);
var composite = new Composite(element.Name.LocalName);
composite.AddRange(element.Elements().Select(CreateComposite));
return composite;
}
这按预期填充了我的合成 - 太棒了!但是,我现在希望我的组合通过 IEnumerable 的实现成为 return 迭代器。所以我尝试了这个
public class Composite : IComposite, IEnumerable<IComponent>
{
// return an iterator?
private readonly List<IComponent> _children = new List<IComponent>();
public Composite(string name)
{
Name = name;
}
public string Name { get; }
public void AddRange(IEnumerable<IComponent> components)
{
_children.AddRange(components);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<IComponent> GetEnumerator()
{
foreach (var child in _children)
{
yield return child;
}
}
}
但这只会遍历组件的顶层,即嵌套在 _children
中的任何组件都不会 returned。我如何更新它以递归遍历所有组件?
您可以使用 Linq 递归地实现遍历,如下所示。
public IEnumerable<IComponent> GetSuccessors()
{
return _children
.Concat(_children.SelectMany(iChild => iChild.GetSuccessors());
}
如果需要depht-first traversal,您可以使用以下实现。
public IEnumerable<IComponent> GetSuccessors()
{
return _children
.SelectMany(iChild => new IComponent[]{iChild}.Concat(iChild.GetSuccessors()));
}
或者,如果您需要使用初始语法,您可以使用以下内容。
public IEnumerator<IComponent> GetEnumerator()
{
var Successors
= _children
.SelectMany(iChild => new IComponent[]{iChild}.Concat(iChild.GetSuccessors()));
foreach (var iSuccessor in Successors)
{
yield return iSuccessor;
}
}
你可以像这样递归迭代(它将以深度优先的方式进行迭代):
public interface IComposite : IComponent, IEnumerable<IComponent>
{
void AddRange(IEnumerable<IComponent> components);
}
public IEnumerator<IComponent> GetEnumerator()
{
foreach (var child in _children)
{
yield return child;
var composite = child as IComposite;
if (composite != null) {
foreach (var sub in composite) {
yield return sub;
}
}
}
}
如果您想避免转换为 IComposite
- 您需要重新设计您的界面并使您的 Composite
包含另一个 IComposite
的列表而不是组件。然后 ILeft
也将成为 IComposite
与虚拟实现。
我已经实现了如下的复合模式
public interface IComponent
{
string Name { get; }
}
public interface IComposite : IComponent
{
void AddRange(IEnumerable<IComponent> components);
}
public interface ILeaf : IComponent
{
string Content { get; }
string Parent { get; }
}
public class Composite : IComposite
{
// return an iterator?
private readonly List<IComponent> _children = new List<IComponent>();
public Composite(string name)
{
Name = name;
}
public string Name { get; }
public void AddRange(IEnumerable<IComponent> components)
{
_children.AddRange(components);
}
}
public class Leaf : ILeaf
{
public string Name { get; }
public string Content { get; }
public string Parent { get; }
public Leaf(string name, string content, string parent)
{
Name = name;
Content = content;
Parent = parent;
}
}
我从 xml 文件中填充了如下复合材料
var collection = XElement.Load(@"C:\somexml.xml");
var composite = CreateComposite(collection);
哪里
public IComponent CreateComposite(XElement element)
{
if (!element.HasElements)
return new Leaf(element.Name.LocalName, element.Value, element.Parent.Name.LocalName);
var composite = new Composite(element.Name.LocalName);
composite.AddRange(element.Elements().Select(CreateComposite));
return composite;
}
这按预期填充了我的合成 - 太棒了!但是,我现在希望我的组合通过 IEnumerable 的实现成为 return 迭代器。所以我尝试了这个
public class Composite : IComposite, IEnumerable<IComponent>
{
// return an iterator?
private readonly List<IComponent> _children = new List<IComponent>();
public Composite(string name)
{
Name = name;
}
public string Name { get; }
public void AddRange(IEnumerable<IComponent> components)
{
_children.AddRange(components);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<IComponent> GetEnumerator()
{
foreach (var child in _children)
{
yield return child;
}
}
}
但这只会遍历组件的顶层,即嵌套在 _children
中的任何组件都不会 returned。我如何更新它以递归遍历所有组件?
您可以使用 Linq 递归地实现遍历,如下所示。
public IEnumerable<IComponent> GetSuccessors()
{
return _children
.Concat(_children.SelectMany(iChild => iChild.GetSuccessors());
}
如果需要depht-first traversal,您可以使用以下实现。
public IEnumerable<IComponent> GetSuccessors()
{
return _children
.SelectMany(iChild => new IComponent[]{iChild}.Concat(iChild.GetSuccessors()));
}
或者,如果您需要使用初始语法,您可以使用以下内容。
public IEnumerator<IComponent> GetEnumerator()
{
var Successors
= _children
.SelectMany(iChild => new IComponent[]{iChild}.Concat(iChild.GetSuccessors()));
foreach (var iSuccessor in Successors)
{
yield return iSuccessor;
}
}
你可以像这样递归迭代(它将以深度优先的方式进行迭代):
public interface IComposite : IComponent, IEnumerable<IComponent>
{
void AddRange(IEnumerable<IComponent> components);
}
public IEnumerator<IComponent> GetEnumerator()
{
foreach (var child in _children)
{
yield return child;
var composite = child as IComposite;
if (composite != null) {
foreach (var sub in composite) {
yield return sub;
}
}
}
}
如果您想避免转换为 IComposite
- 您需要重新设计您的界面并使您的 Composite
包含另一个 IComposite
的列表而不是组件。然后 ILeft
也将成为 IComposite
与虚拟实现。