0

我最近询问了循环依赖。答案是专门开发一个关于接口的项目(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 培训练习。

4

2 回答 2

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 是关于代码的逻辑组织,而不是物理组织。这个对多个项目和一个解决方案的好处的回答列出了拥有多个项目的充分理由。

于 2018-10-22T19:43:06.323 回答
0

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

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

// 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”类来保存字符之间的某种共享功能/属性。

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

于 2018-10-27T00:57:33.170 回答