我对访问者模式有疑问,我目前有两个程序集。我的第一个程序集包含几个接口。
public interface INode
{
void Visit(INodeVisitor visitor);
}
public interface INodeVisitor
{
void VisitContainer(IContainer container);
}
public interface IContainer : INode
{
}
我的第二次集会
class Program
{
static void Main(string[] args)
{
ContainerVisitor visitor = new ContainerVisitor();
visitor.VisitContainer(new Container());
}
}
public class ContainerVisitor : INodeVisitor
{
public void VisitContainer(IContainer value)
{
Container container = value as Container;
// Do some stuff...
}
}
public class Container : IContainer
{
public void Visit(INodeVisitor visitor)
{
visitor.VisitContainer(this);
}
}
我想要做的是避免在ContainerVisitor类中进行强制转换,我想直接引用Container。我无法更改接口INodeVisitor接口以使用Container。有任何想法吗?我应该演员吗?
干杯
罗汉
答案 0 :(得分:3)
强制转换是不可避免的,但您可以将其抽象出来以将其从实际的ContainerVisitor类中删除。
public class NodeVisitor<T> : INodeVisitor where T : IContainer {
public void VisitContainer(T node) {
var container = node as T;
if ( container != null ) {
VisitTyped(container);
}
}
protected abstract VisitContainerTyped(T container);
}
现在,ContainerVisitor可以从NodeVisitor派生并避免强制转换
public class ContainerVisitor : NodeVisitor<Container>{
protected override void VisitContainerTyped(Container container){
// Do some stuff...
}
}
答案 1 :(得分:1)
我不认为有效认为它是Container
实例。完全有效地,我可以编写自己的IContainer
实现,并且您的实现会扼杀它,打破了基于接口的抽象的全部要点。你也不能(有效地)只是改变API来接受Container
(使用显式实现来支持IContainer
),因为我可以使用接口而不是类:
INodeVisitor visitor = new ContainerVisitor();
visitor.VisitContainer(myBespokeContainer);
如果你想从基类中获得某些东西的可选支持,那么你将不得不使用“as”来检测它。还有别的东西,你正在打破抽象。
答案 2 :(得分:1)
除非您可以更好地定义IContainer界面,否则您将无法避免强制转换。正如Marc所说,这违背了基于接口的抽象的目的。
public interface IContainer : INode
{
void Add(IComponent component);
void Add(IComponent component, string name);
void Remove(IComponent component);
ComponentCollection Components { get; }
}
使用更好定义的IContainer,您的访客将无需进行任何投射。
public class ContainerVisitor : INodeVisitor
{
public void VisitContainer(IContainer container)
{
foreach (IComponent component in container.Components)
{
// ...
}
}
}