简体   繁体   English

C#实现可观察模式

[英]C# Implement Observable Pattern

I`m trying to implement observable pattern using C#. 我正在尝试使用C#实现可观察的模式。 In my sample code I have two kind of soldiers archer two classes: Archer and Swordsman they implement Soldier interface. 在我的示例代码中,我有两种类型的士兵弓箭手,分别是两种: ArcherSwordsman,它们实现了Soldier接口。 Soldier interface has has four methods: 士兵界面有四种方法:

  • Attack() - command the soldier to attack the enemy Attack()-命令士兵攻击敌人
  • Died() - this method doesn`t matter in that example Died()-在该示例中,此方法无关紧要
  • Kill() - command our soldier to kill the enemy Kill()-命令我们的士兵杀死敌人
  • BattleCry() - celebration of ALL my soldiers after emeny is killed BattleCry()-庆祝emeny被杀死后我所有的士兵

and one property bool IsEnemyKilled - when Kill() method is called IsEnemyKilled becomes true. 还有一个属性IsEnemyKilled当调用Kill()方法时,IsEnemyKilled变为true。

And here is what I want to do: I know that to implement Observer Pattern I need Provider and Observers. 这就是我想要做的:我知道要实现观察者模式,我需要提供者和观察者。 When one of soldiers eg archer - kills an enemy archer.Kill(); 当一名士兵,例如弓箭手-杀死敌人的弓箭手时archer.Kill(); . IsEnemyKilled become true (this is my provider) and all my other soldiers (my observers) eg swordsman and another archer must be notified that IsEnemyKilled is true and they must call BattleCry(). IsEnemyKilled变为真实(这是我的提供者),并且我的所有其他士兵(我的观察员)(例如剑客和另一个弓箭手)必须被告知IsEnemyKilled是真实的,并且他们必须调用BattleCry()。

I`m confused how to do it. 我很困惑该怎么做。 I will appreciate if anyone suggest in idea. 如果有人提出建议,我将不胜感激。 Here is my sample code. 这是我的示例代码。

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();
    }
}

You need to attach the Subject (some soldier) to the observer (some other soldier). 您需要将主题(某些士兵)附加到观察者(其他士兵)上。
To achieve this I first added three new members to the Soldier-Interface: 为了实现这一点,我首先在士兵接口中添加了三个新成员:

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

The event here is to notify the subject and firing it is achieved using the setter of the property. 这里的事件是通知主题并使用该属性的setter触发它。 I changed the property as follows: 我将属性更改如下:

private bool isEnemyKilled;

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

The implementation of Attach and Detach are as follows: AttachDetach的实现如下:

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

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

Since I see a lot of repetition when you have to implement this for both Soldiers, consider changing Soldier from an interface to an abstract class . 由于我在必须对两个Soldier都实施此操作时看到很多重复,因此请考虑将Soldierinterface更改为abstract class

When you've done all that, you will need to attach (all) the Soldiers together (of course according to your desired game-logic). 完成所有这些操作后,您将需要将(所有)士兵附在一起(当然要根据所需的游戏逻辑)。
One way of keeping track of all Soldiers would be a static List<Soldier> in (your now abstract class) Soldier where each Soldier adds himself, once created. 跟踪所有士兵的一种方法是(现在是抽象类) Soldier中的static List<Soldier> ,每个士兵一旦创建便会添加自己。 But you can do whatever you want there. 但是您可以在那里做任何您想做的事情。

These are just some ideas and are not a full blown observer-pattern. 这些只是一些想法,并不是完整的观察者模式。 Since you asked for ideas I wanted to throw in some. 自从您提出想法以来,我想提出一些想法。 Hope it brings you on the right track. 希望它能带您走上正确的道路。

Another tip: if you only need the property IsEnemyKilled to notify the others, you can simply leave it out and invoke the event EnemyKilled directly instead of setting IsEnemyKilled to true . 另一个提示:如果只需要属性IsEnemyKilled来通知其他人,则可以简单地将其保留而直接调用事件EnemyKilled ,而不是将IsEnemyKilled设置为true

I suggest adding subscribers (observers) to your povider (the archer). 我建议将订阅者(观察者)添加到您的povider(弓箭手)中。 That way, your Archer will have soldiers subscribed to the archer's attacks. 这样,您的弓箭手将让士兵订阅弓箭手的进攻。

Lat's break it down. 拉特将其分解。

Your Archer should have his observers: 您的弓箭手应该有他的观察者:

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

        public void Attack()
...

Now lets notify about victory: 现在让我们通知胜利:

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

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

Finally, Lets subscribe our soldier: 最后,让我们订阅我们的士兵:

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

static void Main(string[] args)
        {

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

You can (and should) add a alert method to your Soldier class, that way you could call it instead of the BattleCry method. 您可以(并且应该)将Alert方法添加到Soldier类,这样您就可以调用它而不是BattleCry方法。

I find the following article a good example: https://exceptionnotfound.net/the-daily-design-pattern-observer/ 我发现以下文章是一个很好的例子: https : //exceptionnotfound.net/the-daily-design-pattern-observer/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM