سؤال

Hi I'm trying to create abstract class Person and two child classes Student and Staff. Person class also has an observer that is notified by a Practical class. But Students will be notified only about question number changed and Staff about student's feel-good factor. That factor can be marked at any time by any student. I've managed to get observer working but only with Person class. I know I hav to make it abstract and then create Staff and Student classes but I just can't get my head round it. Any help would be great. Thanks Here s the code:

namespace ConsoleApplication1
{
class Practical : IPractical    //Practical class
{
    private String QuestionNumber;// the state which observers are interested in.
    private String Factor;
    private ArrayList observers;    // the collection of observers attached to this subject.

    public Practical(String qnumber, String f)
    {
        QuestionNumber = qnumber;
        Factor = f;
        observers = new ArrayList();
    }

    public void AddObserver(IPerson o) { observers.Add(o); }
    public void RemoveObserver(IPerson o) { observers.Remove(o); }

    public void NotifyObserverQN()
    {
        foreach (IPerson o in observers) { o.Update(QuestionNumber); }
    }

    public void NotifyObserverFactor()
    {
        foreach (IPerson o in observers) { o.Update(Factor); }
    }

    public String QN
    {
        get { return QuestionNumber; }
        set
        {
            QuestionNumber = value;
            NotifyObserverQN();     //notify about new question
        }
    }

    public String Fc
    {
        get { return Factor; }
        set
        {
            Factor = value;
            NotifyObserverFactor();     //notify about new ffctor
        }
    }
   }

      interface IPractical  //IPractical interface
     {
           void AddObserver(IPerson o);
           void RemoveObserver(IPerson o);
           void NotifyObserverQN();
           void NotifyObserverFactor();
    }



  class Person : IPerson
   {

    private string id;
    public Person(string i) { id = i; }
    public void Update(Object o)     { Console.WriteLine(" {0} notified about {1} .", id, o.ToString()); }

}

  interface IPerson     //Observer interface
   {
      void Update(Object o);

    }



 class Observer
  {

    public static void Main()
    {
        Console.WriteLine("\n\nStart\n\n");
        Practical practical = new Practical("Question", "Factor");
        IPerson a, b, c;
        a = new Person(" Student_1 ");
        b = new Person(" Student_2 ");
        c = new Person(" Staff_1   ");

        practical.AddObserver(a);
        practical.AddObserver(b);
        practical.AddObserver(c);

        practical.QN = "Question 1";   // all students notifie about Question 1 
        practical.Fc = "Feel-Good";
        practical.QN = "Question 2";   // all students notifie about Question 2
        practical.Fc = "Feel-Bad";

        Console.WriteLine("\n\nEnd\n\n");
    }

   } 

 }
هل كانت مفيدة؟

المحلول

Ideally, you need an explicit casting which check a particular observer is of type Student or Staff. In such case, you can generalize your notification method as below instead of writing two notification methods.

    public void Notify()
    {
        foreach (IPerson o in observers)
        {
            if (IPerson is Student)
                o.Update(QuestionNumber);// Student - question number 
            else
                o.Update(Factor);//Staff -  feel-good factor

        }
    }

As per the request on how inheritance works in this case;

 public abstract class Person : IPerson
    {
        private string id;
        public Person(){}
        public Person(string i)
        {
            id = i;
        }
        public abstract void Update(Object o);
    }
    public class Student:Person
{
    public Student(){}
    public Student(string i):base(i)
    {
    }
    public override void Update(object o)
    {
        //whatever you wanted to do with Student
    }
}
public class Staff : Person
{
     public Staff(){}
     public Staff(string i)
         : base(i)
    {
    }
    public override void Update(object o)
    {
        //whatever you wanted to do with Staff
    }
}    
    interface IPerson     //Observer interface
    {
        void Update(Object o);

    }

نصائح أخرى

I would like to add that in C# I prefer to implement observers via events. Instead of the observer having to know who is observing them and their types, you raise events in the observed class. In your case, you would raise the QuestionChanged and FactorChanged events in the Practical class. When you create your observers, you register them with your staff and student classes, and they will select which event they are interested in. This way no one has to know what type the other one is.

Something like this (pseudo-code, might not compile):

public class Practical {
    ...
public event EventHandler QNChanged;
public event EventHandler FcChanged;
public String QN
{
    get { return QuestionNumber; }
    set
    {
        QuestionNumber = value;
        OnQNChanged();     //notify about new question
    }
}

public String Fc
{
    get { return Factor; }
    set
    {
        Factor = value;
        OnFcChanged();     //notify about new ffctor
    }
}

protected void OnFcChanged(){
    if(this.FcChanged != null) {
         FcChanged(this, null);
    }
}

protected void OnQnChanged(){
    if(this.QnChanged != null) {
         QnChanged(this, null);
    }
}
...
}

public class Student {
     public Student(Practical practical){
          practical.QnChanged += Update;
     }

     public void Update(object sender, EventArgs args){
          Practical practical = (Practical) sender;
          // do something with practical
     }
}

public class Staff{
     public Staff(Practical practical){
          practical.FnChanged += Update;
     }

     public void Update(object sender, EventArgs args){
          Practical practical = (Practical) sender;
          // do something with practical
     }
}

class Observer
{

public static void Main()
{
    ....
    var practical = new Practical("Question", "Factor");

    var a = new Student(practical);
    var b = new Staff(practical);

    practical.QN = "Question 1";   // all students notified about Question 1 
    practical.Fc = "Feel-Good";
    practical.QN = "Question 2";   // all students notified about Question 2
    practical.Fc = "Feel-Bad";
    ....

  }

 } 

Note: you don't have to have the observed item in the constructor, you can also add a method to register it, if you wish, it just made the example simpler. I.e, your staff and student could implement this interface:

 public interface IPracticalObserver {
      void RegisterPractical(IPractical practical);
      void Update(object practical, EventArgs args);
 }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top