C#中观察者模式的实现:事件

"C#中观察者模式的实现:事件"

Posted by 小镇青年 on February 24, 2019

本文为HeadFirst读书笔记

事件与观察者模式

C#中的事件是一种典型的观察者模式winform程序中,可订阅按钮等控件引发的事件。

事件具有以下属性(来自MicrosoftDoc):

  • 发行者确定何时引发事件;订户确定对事件作出何种响应。
  • 一个事件可以有多个订户。 订户可以处理来自多个发行者的多个事件。
  • 没有订户的事件永远也不会引发。
  • 事件通常用于表示用户操作,例如单击按钮或图形用户界面中的菜单选项。
  • 当事件具有多个订户时,引发该事件时会同步调用事件处理程序。 若要异步调用事件,请参阅 Calling Synchronous Methods Asynchronously
  • 在 .NET Framework 类库中,事件基于 EventHandler 委托和 EventArgs 基类。

示例

以下是参照张阳-博客园-三种观察者模式的C#实现的示例

智能闹钟例子

闹钟响铃后,打开床头灯,打开窗帘,播放音乐。

闹钟相关方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private void TurnOnTheAlarm(DateTime? alarmTime)    
{
    if (!alarmTime.HasValue)
    {
        return;
    }
    var cancelToken = new CancellationTokenSource();
    var task = new Task(() =>
    {
        while (!cancelToken.IsCancellationRequested)
        {
            if (DateTime.Now >= alarmTime.Value)
            {
                // 闹铃时间到了
                Alarm();
                cancelToken.Cancel();
            }
            else
            {
                logger.Info($"现在时间是:{DateTime.Now}");
            }
            cancelToken.Token.WaitHandle.WaitOne(TimeSpan.FromSeconds(1));
        }
    }, cancelToken.Token, TaskCreationOptions.LongRunning);
    task.Start();
}

private void Alarm()
{
    AlarmClock alarmClock = new AlarmClock();
    BedsideLamp turnOnTheBedsideLamp = new BedsideLamp(logger, "床头灯", alarmClock);
    Curtains curtains = new Curtains(logger, "窗帘", alarmClock);
    Speaker speaker = new Speaker(logger, "音响", alarmClock);
    alarmClock.DoSomething("闹钟响了,准备起床。");
}

闹钟类及相关事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/// <summary>
/// 闹钟类
/// </summary>
public class AlarmClock
{
    public event EventHandler<CustomEventArgs> AlarmCustomEvent;

    public void DoSomething(string s)
    {
        OnAlarmCustomEvent(new CustomEventArgs(s));
    }
    protected virtual void OnAlarmCustomEvent(CustomEventArgs e)
    {
        EventHandler<CustomEventArgs> handler = AlarmCustomEvent;
        if (handler != null)
        {
            //e.Message += $" at {DateTime.Now}";
            handler(this, e);
        }
    }
}

public delegate void EventHandler(object sender, EventArgs e);

public class CustomEventArgs : EventArgs
{
    public CustomEventArgs(string s)
    {
        message = s;
    }
    private string message;

    public string Message
    {
        get { return message; }
        set { message = value; }
    }
}

订阅闹钟的设备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/// <summary>
/// 床头灯
/// </summary>
public class BedsideLamp
{
    private string id;
    private Logger _logger;
    public BedsideLamp(Logger logger, string ID, AlarmClock pub)
    {
        _logger = logger;
        id = ID;
        pub.AlarmCustomEvent += HandleCustomEvent;
    }
    void HandleCustomEvent(object sender, CustomEventArgs e)
    {
        _logger.LogImportantInfo($"【{id}】 收到消息: {e.Message}");
        _logger.LogImportantInfo($"【{id}】 已打开床头灯");
    }
}
/// <summary>
/// 窗帘
/// </summary>
public class Curtains
{
    private string id;
    private Logger _logger;
    public Curtains(Logger logger, string ID, AlarmClock pub)
    {
        _logger = logger;
        id = ID;
        pub.AlarmCustomEvent += HandleCustomEvent;
    }
    void HandleCustomEvent(object sender, CustomEventArgs e)
    {
        _logger.LogImportantInfo($"【{id}】 收到消息: {e.Message}");
        _logger.LogImportantInfo($"【{id}】 已打开窗帘");
    }
}
/// <summary>
/// 音箱
/// </summary>
public class Speaker
{
    private string id;
    private Logger _logger;
    public Speaker(Logger logger, string ID, AlarmClock pub)
    {
        _logger = logger;
        id = ID;
        pub.AlarmCustomEvent += HandleCustomEvent;
    }
    void HandleCustomEvent(object sender, CustomEventArgs e)
    {
        _logger.LogImportantInfo($"【{id}】 收到消息: {e.Message}");
        _logger.LogImportantInfo($"【{id}】 开始播放音乐");
    }
}

参考

事件(C# 编程指南)

本文GitHub源码

三种观察者模式的C#实现