سؤال

ولدي سؤال بخصوص نمط الزوار، ولدي حاليا اثنين من التجمعات. يحتوي بلدي أول جمعية واجهات عدة.

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، أريد أن مرجع الحاويات مباشرة. لا أستطيع تغيير واجهة واجهة 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. يمكن I، تماما على نحو صحيح، يكتب لي تنفيذ IContainer الخاصة، وسيكون التطبيق الخاص بك خنق عليه، وكسر بيت القصيد من التجريد القائم على واجهة. يمكنك أيضا لا (صحيحا) مجرد تغيير API لقبول Container (باستخدام تطبيق صريح لدعم IContainer)، لأنني يمكن استخدام واجهة بدلا من الطبقة:

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)
        {
            // ...
        }
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top