将复合模式应用于一般图形模型
apply composite pattern to general graph models
我想建立一个数据模型,主要由一个图组成,稍后要遍历。特殊要求:图中的节点可以是要执行的动作,也可以是带有另一个动作或容器图的容器。遍历时,必须检查当前节点是否为容器,如果是,则开始子图的遍历。
这是如何实现的?一个数据模型应该是什么样子,才能搭建出下图这样的结构?
到目前为止我得到了一些 类。有几种动作类型,因此我在这里使用一个界面
public interface IAction : IContainer
{
public ActionType ActionType{ get; set; }
public Name { get; set; }
}
容器只包含一个名称和一个自引用。我最初也尝试通过使用接口来完成此操作,但后来我只能访问接口属性,而不能访问容器属性
public interface IContainer
{
public string Name { get; set; }
}
public class Container : IContainer
{
public string Name { get; set; }
public IContainer Content { get; set; }
}
主要的测试用法如下所示:
myJob.Content = new QuikGraph.BidirectionalGraph<IContainer, QuikGraph.Edge<IContainer>>();
myJob.Content.AddVertex(new MyCustomAction()
{
ActionType = ActionType.MyCustomAction,
Name = "Test"
});
myJob.Content.Vertices.First().Name // only property I could access, no action-specific ones
我做错了什么?
我认为您在 IContainer
中遗漏了一个操作(方法),该操作可从图中的任何节点调用,并且其行为符合您的预期(将调用转发到其所有封闭操作的容器和执行实际操作的动作)。
此外,与其在 Container
中保存对 IContainer
的单个引用,不如拥有一个子集合 IContainer
,因为在您的图表中,一个容器有 3 个操作。
请参阅 Composite pattern 了解更多说明。
public interface IContainer
{
string Name { get; set; }
void DoWork();
}
public sealed class Action1 : IAction
{
public override DoWork()
{
//Do the real work
}
}
public sealed class Container : IContainer
{
private readonly IReadOnlyList<IContainer> _children;
public Container(IEnumerable<IContainer> children) => _children = children.ToList();
public override DoWork()
{
foreach(var child in _children)
{
child.DoWork();
}
}
}
这是我想出的结果。我花了一些时间才知道如何对此建模,但最终我按照@Spotted 的建议应用了复合模式。我从 类 中完全删除了 quikgraph 库并将其外包给另一个服务,我只在我想遍历图形或检查周期等时调用它...
此外,我选择不 link 实体直接相互联系,而是通过名称,否则序列化会输出双倍的信息(节点可能被多次引用)。
public interface IContainer
{
string Name { get; set; }
IList<string> DependsOn { get; set; }
void DoWork();
void AddDependency(string name)
}
public interface IAction : IContainer
{
// more common stuff
}
public sealed class Action1 : IAction
{
public string Name { get; set; }
IList<string> DependsOn { get; set; }
public DoWork()
{
//Do the real work
}
public void AddDependency(string name)
{
this.DependsOn.Add(name);
}
}
public sealed class Container : IContainer
{
public string Name { get; set; }
public IList<string> DependsOn { get; set; }
public IList<IContainer> SubGraph { get; set; }
public override DoWork()
{
foreach(var item in SubGraph)
{
item.DoWork();
}
}
public void AddSubGraph(IList<IContainer> subGraph)
{
this.SubGraph = subGraph;
}
}
谢谢你的帮助,伙计!
我想建立一个数据模型,主要由一个图组成,稍后要遍历。特殊要求:图中的节点可以是要执行的动作,也可以是带有另一个动作或容器图的容器。遍历时,必须检查当前节点是否为容器,如果是,则开始子图的遍历。
这是如何实现的?一个数据模型应该是什么样子,才能搭建出下图这样的结构?
到目前为止我得到了一些 类。有几种动作类型,因此我在这里使用一个界面
public interface IAction : IContainer
{
public ActionType ActionType{ get; set; }
public Name { get; set; }
}
容器只包含一个名称和一个自引用。我最初也尝试通过使用接口来完成此操作,但后来我只能访问接口属性,而不能访问容器属性
public interface IContainer
{
public string Name { get; set; }
}
public class Container : IContainer
{
public string Name { get; set; }
public IContainer Content { get; set; }
}
主要的测试用法如下所示:
myJob.Content = new QuikGraph.BidirectionalGraph<IContainer, QuikGraph.Edge<IContainer>>();
myJob.Content.AddVertex(new MyCustomAction()
{
ActionType = ActionType.MyCustomAction,
Name = "Test"
});
myJob.Content.Vertices.First().Name // only property I could access, no action-specific ones
我做错了什么?
我认为您在 IContainer
中遗漏了一个操作(方法),该操作可从图中的任何节点调用,并且其行为符合您的预期(将调用转发到其所有封闭操作的容器和执行实际操作的动作)。
此外,与其在 Container
中保存对 IContainer
的单个引用,不如拥有一个子集合 IContainer
,因为在您的图表中,一个容器有 3 个操作。
请参阅 Composite pattern 了解更多说明。
public interface IContainer
{
string Name { get; set; }
void DoWork();
}
public sealed class Action1 : IAction
{
public override DoWork()
{
//Do the real work
}
}
public sealed class Container : IContainer
{
private readonly IReadOnlyList<IContainer> _children;
public Container(IEnumerable<IContainer> children) => _children = children.ToList();
public override DoWork()
{
foreach(var child in _children)
{
child.DoWork();
}
}
}
这是我想出的结果。我花了一些时间才知道如何对此建模,但最终我按照@Spotted 的建议应用了复合模式。我从 类 中完全删除了 quikgraph 库并将其外包给另一个服务,我只在我想遍历图形或检查周期等时调用它...
此外,我选择不 link 实体直接相互联系,而是通过名称,否则序列化会输出双倍的信息(节点可能被多次引用)。
public interface IContainer
{
string Name { get; set; }
IList<string> DependsOn { get; set; }
void DoWork();
void AddDependency(string name)
}
public interface IAction : IContainer
{
// more common stuff
}
public sealed class Action1 : IAction
{
public string Name { get; set; }
IList<string> DependsOn { get; set; }
public DoWork()
{
//Do the real work
}
public void AddDependency(string name)
{
this.DependsOn.Add(name);
}
}
public sealed class Container : IContainer
{
public string Name { get; set; }
public IList<string> DependsOn { get; set; }
public IList<IContainer> SubGraph { get; set; }
public override DoWork()
{
foreach(var item in SubGraph)
{
item.DoWork();
}
}
public void AddSubGraph(IList<IContainer> subGraph)
{
this.SubGraph = subGraph;
}
}
谢谢你的帮助,伙计!