C#实现可观察模式

时间:2019-04-28 16:07:22

标签: c# design-patterns observer-pattern observers

我正在尝试使用C#实现可观察的模式。在我的示例代码中,我有两种类型的士兵弓箭手,分别是 Archer Swordsman ,它们实现了 Soldier 接口。 士兵界面有四种方法:

  • Attack()-命令士兵攻击敌人
  • Died()-此方法在该示例中无关紧要
  • Kill()-命令我们的士兵杀死敌人
  • BattleCry()-庆祝我们的士兵被杀死之后 ALL

和一个属性布尔IsEnemyKilled-当调用Kill()方法IsEnemyKilled时变为真。

这是我想做的: 我知道要实现观察者模式,我需要提供者和观察者。 当一名士兵弓箭手-杀死敌人archer.Kill();。  IsEnemyKilled成为真实的(这是我的提供者),而我的所有其他士兵(我的观察员)例如必须通知剑客和另一个弓箭手IsEnemyKilled是正确的,并且他们必须调用BattleCry()。

我很困惑该怎么做。如果有人提出建议,我将不胜感激。这是我的示例代码。

namespace ImplementObservable
{
    class Program
    {
        static void Main(string[] args)
        {

            var archer = new Archer();
            var swordsman = new Swordsman();
            archer.Attack();
            archer.Kill();
            Console.ReadKey();
        }
    }

    public class Archer : Soldier
    {
        bool IsEnemyKilled;
        // watch somehow prop "IsEnemyKilled" and if it changes to true call BattleCry() for all units

        public void Attack()
        {
            IsEnemyKilled = false;
            Console.WriteLine("Archer attack!");
        }

        public void Died()
        {
            IsEnemyKilled = false;
            Console.WriteLine("Archer died :(");
        }

        public void Kill()
        {
            IsEnemyKilled = true;
            Console.WriteLine("Archer killed enemy! Hurray!!");
        }

        public void BattleCry()
        {
            Console.WriteLine("Archer: Go for victory !");
        }
    }

    public class Swordsman : Soldier
    {
        bool IsEnemyKilled;
        // watch somehow prop "IsEnemyKilled" and if it changes to true call BattleCry() for all units

        public void Attack()
        {
            IsEnemyKilled = false;
            Console.WriteLine("Swordsman attack!");
        }

        public void Died()
        {
            IsEnemyKilled = false;
            Console.WriteLine("Swordsman died :(");
        }
        public void Kill()
        {
            IsEnemyKilled = true;
            Console.WriteLine("Swordsman killed enemy! Hurray!!");
        }

        public void BattleCry()
        {
            Console.WriteLine("Swordsman: Go for victory !");
        }
    }

    public interface Soldier
    {
        void Kill();

        void Attack();

        void Died();

        void BattleCry();
    }
}

2 个答案:

答案 0 :(得分:2)

您需要将主题(某些士兵)附加到观察者(其他士兵)上。
为此,我首先在“士兵界面”中添加了三个新成员:

event Action EnemyKilled;
void Attach(Soldier observer);
void Detach(Soldier observer);

这里的事件是通知主题并使用该属性的setter触发它。我将属性更改如下:

private bool isEnemyKilled;

private bool IsEnemyKilled {
    get => isEnemyKilled;
    set {
        isEnemyKilled = value;
        if(isEnemyKilled) EnemyKilled?.Invoke();
    }
}

AttachDetach的实现如下:

public void Attach(Soldier observer)
{
    observer.EnemyKilled += BattleCry;
}

public void Detach(Soldier observer)
{
    observer.EnemyKilled -= BattleCry;
}

由于在您必须为两个士兵实施此重复操作时,我会看到很多重复,因此请考虑将Soldierinterface更改为abstract class

完成所有这些操作后,您将需要将(所有)士兵捆绑在一起(当然,这要取决于您想要的游戏逻辑)。
跟踪所有士兵的一种方法是在static List<Soldier>中的Soldier(现在是抽象类)中,一旦创建,每个士兵都会添加自己。但是您可以在那里做任何您想做的事情。

这些只是一些想法,并不是完整的观察者模式。自从您提出想法以来,我想提出一些想法。希望它能带您走上正确的道路。

另一个提示:如果您只需要属性IsEnemyKilled来通知其他人,则可以简单地将其保留而直接调用事件EnemyKilled,而不用将IsEnemyKilled设置为{{1 }}。

答案 1 :(得分:2)

我建议将订阅者(观察者)添加到您的povider(弓箭手)中。 这样,您的弓箭手将有士兵订阅弓箭手的进攻。

拉特将其分解。

您的弓箭手应该有他的观察者:

public class Archer : Soldier
    {
        bool IsEnemyKilled;
        private List<Soldirer> soldiers = new List<Soldier>();

        public void Attack()
...

现在让我们通知胜利:

    public void Attack()
    {
        IsEnemyKilled = false;
        Console.WriteLine("Archer attack!");

        soldiers.foreach(soldier => soldier.BattleCry());
    }

最后,让我们订阅我们的士兵:

public class Archer : Soldier {
...
    public void subscribe(Soldier) {
            soldiers.add(soldier);
    }
}

static void Main(string[] args)
        {

            var archer = new Archer();
            var swordsman = new Swordsman();
        ...

您可以(并且应该)将Alert方法添加到Soldier类中,从而可以调用它而不是BattleCry方法。

我发现以下文章是一个很好的例子: https://exceptionnotfound.net/the-daily-design-pattern-observer/