【问题标题】:Cyclic depenency: IVisitor and Datas循环依赖:IVisitor 和 Dates
【发布时间】:2019-03-26 22:43:26
【问题描述】:

我最近询问了循环依赖。答案是专门开发一个关于接口的项目 (MyProject.Abstractions)。现在,这个项目是另一个循环依赖的原因,具有访问者模式。

namespace MyProject.Abstractions
{
    public interface ICharacter { }

    public interface ICharacterVisitor
    {
        // References MyProject.Characters
        void Visit(Warrior warrior);
        void Visit(Wizard wizard);
    }
}

namespace MyProject.Characters
{
    // References MyProject.Abstractions
    public abstract class CharacterBase : ICharacter { }

    public class Warrior : CharacterBase { }
    public class Wizard : CharacterBase { }
}

这是否意味着我的 ICharacterVisitor 应该在我的 MyProject.Characters 项目中?我将整个解决方案用作我的 SOLID 培训练习。

【问题讨论】:

  • void Visit(IWarrior warrior) 将帮助您将依赖关系从具体类转移到抽象。这里的问题取决于具体的 Warrior 类,如果你依赖于抽象的 IWarrior 接口,这个循环依赖就会消失

标签: c# .net solid-principles visitor-pattern cyclic-dependency


【解决方案1】:

访问者是一种适用于现有结构但不是其中一部分的工具。因此,我会将访问者与您正在访问的数据分开。

namespace MyProject.Abstractions.Characters
{
    public interface ICharacter { }
}
using MyProject.Abstractions.Characters;

namespace MyProject.Characters
{
    public abstract class CharacterBase : ICharacter { }

    public class Warrior : CharacterBase { }
    public class Wizard : CharacterBase { }
}
using MyProject.Abstractions.Characters;
using MyProject.Characters;

namespace MyProject.Abstractions.Visitors
{
    public interface ICharacterVisitor
    {
        // References MyProject.Characters
        void Visit(Warrior warrior);
        void Visit(Wizard wizard);
    }
}
using MyProject.Abstractions.Characters;
using MyProject.Abstractions.Visitors
using MyProject.Characters;

namespace MyProject.Visitors
{
    // Concrete visitors here
}

您不一定需要为每个命名空间创建一个单独的项目。访客资料可能与MyProject.Characters 在同一个项目中。 SOLID 是关于代码的逻辑组织,而不是物理组织。这个对benefits of multiple Projects and One Solution 的回答列出了拥有多个项目的充分理由。

【讨论】:

    【解决方案2】:

    就其本质而言,访问者模式确实倾向于引入循环依赖——访问者接口必须知道它所操作的所有不同类,并且每个类都必须以某种方式知道如何在访问者上调用正确的方法,这意味着知道访问者类。

    可以通过执行以下操作来打破这种循环依赖:

    // Abstractions project
    interface ICharacter
    {
        string Name { get; } 
    }
    interface IWarrior : ICharacter
    {
        void Attack();
    }
    interface IWizard : ICharacter
    {
        void CastSpell();
    }
    interface IVisitor
    {
        void Visit(IWarrior w);
        void Visit(IWizard w);
    }
    // implementations project
    abstract class CharacterBase : ICharacter
    {
        public string Name { get; }
        public abstract void Accept(IVisitor v);
    }
    class Warrior : CharacterBase, IWarrior
    {
        public void Attack()
        {
            // do warrior things
        }
        public override void Accept(IVisitor v)
        {
            v.Visit(this);
        }
    }
    class Wizard : CharacterBase, IWizard
    {
        public void CastSpell()
        {
            // do wizardly things
        }
        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }
    

    假设您确实需要“CharacterBase”类来保存角色之间的某种共享功能/属性。

    这是否值得您必须打个电话,因为访客模式的性质是真正的问题 - 您将来添加更多字符类型的可能性有多大?您增加更多访问者的可能性有多大?有没有一种方法可以让每种类型的角色自行决定在特定场景中需要采取哪些行动?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-18
      • 1970-01-01
      • 2016-02-27
      • 2021-04-24
      • 1970-01-01
      • 1970-01-01
      • 2010-09-12
      相关资源
      最近更新 更多