Visitorパターン、キャストする必要性を取り除きます
-
21-08-2019 - |
質問
私は現在、2つのアセンブリを持って、ビジターパターンについて質問があります。私の最初のアセンブリは、いくつかのインタフェースが含まれています。
public interface INode
{
void Visit(INodeVisitor visitor);
}
public interface INodeVisitor
{
void VisitContainer(IContainer container);
}
public interface IContainer : INode
{
}
そして、私の第2組立
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クラスにキャストする必要性を避けるためですが、私は直接コンテナを参照したいです。私はコンテナを使用するインターフェイスのINodeVisitorインタフェースを変更することはできません。何か案は?私はちょうどキャストべきでしょうか?
乾杯
ロアン
解決
キャストは避けられないですが、実際の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...
}
}
他のヒント
私はそれがの有効なのそれはContainer
インスタンスであると仮定することはないと思います。私は、完全に有効に、私自身のIContainer
の実装を書くことができ、そして、あなたの実装では、インターフェイスベースの抽象化の全体のポイントを壊し、それにチョークでしょう。私はクラスではなくインタフェースを使用することができので、あなたはまた、(有効に)ただ、(Container
をサポートするために、明示的な実装を使用して)IContainer
を受け入れるようにAPIを変更することはできません。
INodeVisitor visitor = new ContainerVisitor();
visitor.VisitContainer(myBespokeContainer);
あなたは基本クラスから何かをオプションでサポートが必要な場合は、その後、あなたはそれを検出するため「として、」使用する必要があるとしています。他に何か、あなたは抽象化を壊している。
あなたはもっと自分のいるIContainerインターフェイスを定義することができない限り、あなたはキャストを避けることができなくなります。マークが言うように、それはインターフェイスベースの抽象化の目的に反します。
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)
{
// ...
}
}
}