I`m trying to implement observable pattern using C#. In my sample code I have two kind of soldiers archer two classes: Archer and Swordsman they implement Soldier interface. Soldier interface has has four methods:
and one property bool IsEnemyKilled
- when Kill() method is called IsEnemyKilled becomes 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 e.g. archer - kills an enemy archer.Kill();
.
IsEnemyKilled
become true (this is my provider) and all my other soldiers (my observers) e.g. swordsman and another archer must be notified that IsEnemyKilled
is true and they must call 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. 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:
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
.
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. 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
.