niedziela, 11 października 2009

Observer Pattern

Kolejnym wzorcem projektowym, który omówimy jest Observer Pattern.
Observer Pattern - definiuje związek jeden do wielu pomiędzy obiektami. Dzięki temu gdy obiekt zmieni stan, obiekty zależnie zostaną powiadomione automatycznie.
Schemat ogólny UML:

Schemat składa się z 2 klas + interfejsu. Klasa Subject to klasa którą obserwujemy. Klasa Observer to klasa obserwująca klasę Subject. Dodatkowo każda klasa obserwująca implementuje interfejs IObserver zawierający jedną metodę: Update. W momencie zmiany jakiegoś atrybutu w klasie Subject, następuje wywołanie w pętli metody Update. Dzięki temu wszystkie obserwujące obiekty otrzymują aktualny stan klasy Subject. Jeśli ktoś przyjrzy się dokładnie, to z klasy Subject można wyodrębnić interfejs. Interfejs mógłby zawierać 3 podane metody: dodawania, usuwania i powiadamiania obiektów. Żeby jednak nie zaciemniać na początku samej idei, zatrzymamy się na takim schemacie.

Przykład:
Dosyć prosty przykład gdzie można zastosować opisywany wzorzec:

W momencie wpisywania tekstu w  TexBox1 chcemy, aby reszta naszych texboxów także zawierała wpisywany przez nas tekst. Jest to najprostszy z możliwych przykładów, ale też być może najlepiej obrazujących wykorzystanie tego wzorca. SchematUML przykładu:



Jak widać ConcreteClass dziedziczy po TextBox-ie i implementuje interfejs IObserver. A teraz to co najważniejsze czyli sam kod:

class Subject
{
private TextBox textBox;

private List listOfObservers;

public Subject(TextBox textBox)
{
this.textBox = textBox;
listOfObservers = new List();
textBox.TextChanged+=new EventHandler(textBox_TextChanged);
}

public void AddObserver(IObserver observer)
{
listOfObservers.Add(observer);
}

public void RemoveObserver(IObserver observer)
{
listOfObservers.Remove(observer);
}

private void Notify()
{
foreach (var item in listOfObservers)
{
item.Update(textBox.Text);
}
}

void textBox_TextChanged(object sender, EventArgs e)
{
Notify();
}
}



interface IObserver
{
void Update(string s);
}



class ConcreteClass : TextBox, IObserver
{

#region IObserver Members

public void Update(string s)
{
this.Text = s;
}

#endregion
}



public partial class Form1 : Form
{
private Subject subject;
public Form1()
{
InitializeComponent();
subject = new Subject(textBox1);
subject.AddObserver(concreteClass1);
subject.AddObserver(concreteClass2);
subject.AddObserver(concreteClass3);
subject.AddObserver(concreteClass4);
}
}


Na formatce oczywiście położyć musimy jednego TextBoxa oraz 4 obiekty typu ConcreteClass.

Gdzie wykorzystywać Obserwatora?
Wszędzie tam, gdzie potrzebujemy poinformować o zmianie danego obiektu innym obiektom. Można go wykorzystać podczas interakcji między formatkami oraz wszelkimi kontrolkami. Obrazowym przykładem użycia go jest zmiana w arkuszu kalkulacyjnym wykresu w zależności od wprowadzanych danych.

Brak komentarzy:

Prześlij komentarz