Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Design Patterns via C#.pdf
Скачиваний:
154
Добавлен:
17.03.2016
Размер:
13.25 Mб
Скачать

241

Пример кода

Интерфейс подписчика определен в абстрактном классе Observer.

abstract class Observer

{

public abstract void Update(Subject theChangedSubject);

}

При такой реализации поддерживается несколько издателей для одного подписчика. Передача издателя в качестве параметра метода Update позволяет подписчику определить, состояние какого из издателей изменилось.

В абстрактном классе Subject определен интерфейс издателя.

abstract class Subject

{

protected List<Observer> observers = new List<Observer>();

public virtual void Attach(Observer observer)

{

observers.Add(observer); observer.Update(this);

}

public virtual void Detach(Observer observer)

{

observers.Remove(observer);

}

public virtual void Notify()

{

foreach (var o in observers) o.Update(this);

}

}

ClockTimer – это конкретный издатель, который следит за временем и оповещает подписчиков каждую секунду. Класс ClockTimer предоставляет интерфейс для получения отдельных компонентов времени: часы, минуты, секунды и т.д.

class ClockTimer : Subject

{

System.Threading.Timer timer; private TimeSpan currentTime;

static void TimerProc(object o)

{

(o as ClockTimer).Tick();

}

public ClockTimer()

{

timer = new System.Threading.Timer(TimerProc, this, 1000, 1000);

}

public void Tick()

242

{

currentTime = DateTime.Now.TimeOfDay; Notify();

}

public int GetHour()

{

return currentTime.Hours;

}

public int GetMinute()

{

return currentTime.Minutes;

}

public int GetSecond()

{

return currentTime.Seconds;

}

public TimeSpan GetTime()

{

return currentTime;

}

}

Операция Tick вызывается через одинаковые интервалы внутренним таймером, тем самым обеспечивая правильный отсчет времени. При этом обновляется внутреннее состояние объекта ClockTimer и вызывается метод Notify для уведомления подписчиков об изменении времени.

public void Tick()

{

currentTime = DateTime.Now.TimeOfDay; Notify();

}

Класс DigitalClock отображает время в цифровом формате.

class DigitalClock : Observer

{

Label digitalClockLabel; Subject subject;

TimeSpan time;

public Control GetControl

{

get { return digitalClockLabel; }

}

public DigitalClock(Control parent, Subject subject)

{

digitalClockLabel = new Label { Parent = parent }; this.subject = subject;

subject.Attach(this);

}

public override void Update(Subject theChangedSubject)

{

time = (theChangedSubject as ClockTimer).GetTime();

243

digitalClockLabel.BeginInvoke(new Action(Draw));

}

public void Draw()

{

digitalClockLabel.Text = time.ToString("hh\\:mm\\:ss");

}

}

Класс AnalogClock отображает время в аналоговом формате.

class AnalogClock : Observer

{

class AnalogClockPanel : Panel

{

public AnalogClockPanel()

{

SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

DoubleBuffered = true;

}

}

Panel analogClockPanel;

Subject subject;

TimeSpan time;

Point center = new Point(50, 50);

public AnalogClock(Control parent, Subject subject)

{

analogClockPanel = new AnalogClockPanel() { Parent = parent };

analogClockPanel.Size = new System.Drawing.Size(100, 100); this.subject = subject;

subject.Attach(this);

}

public Control GetControl

{

get { return analogClockPanel; }

}

public override void Update(Subject theChangedSubject)

{

time = (theChangedSubject as ClockTimer).GetTime(); analogClockPanel.Invoke(new Action(Draw));

}

public void Draw()

{

analogClockPanel.Refresh();

var g = analogClockPanel.CreateGraphics(); var rr = analogClockPanel.ClientRectangle;

244

rr.Width -= 1; rr.Height -= 1;

g.DrawEllipse(new Pen(Color.Black, 1), rr);

for (int i = 0; i < 12; i++)

{

var rrr = (float)(Math.PI * 2f) / 60f * (float)(i * 5); var from = GetDestinationPoint(rrr, 45);

var to = GetDestinationPoint(rrr, 50); drawLine(g, from, to, new Pen(Color.Blue, 2));

}

drawW(g, (float)(Math.PI * 2f) / 12f * (float)(time.Hours % 12), 30, new Pen(Color.Blue, 5));

drawW(g, (float)(Math.PI * 2f) / 60f * (float)time.Minutes, 45,

new Pen(Color.Green, 3)); drawW(g, (float)(Math.PI * 2f) / 60f * (float)time.Seconds, 50,

new Pen(Color.Red, 2));

}

Point GetDestinationPoint(float radians, int length)

{

int a = center.Y - (int)(Math.Cos(radians) * (float)length); int b = center.X + (int)(Math.Sin(radians) * (float)length); return new Point(b, a);

}

void drawLine(Graphics g, Point from, Point to, Pen p)

{

g.DrawLine(p, from, to);

}

void drawW(Graphics g, float radians, int length, Pen p)

{

drawLine(g, center, GetDestinationPoint(radians, length), p);

}

}

Результат работы программы:

См. Пример к главе: \019_Observer\007_ObserverClocks

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]