观察者模式

  • 观察者模式(Observe)
    • 动机

      在软件构建过程中,我们需要为某些对象建立一种 (通知依赖关系)


      —— 一个对象 ***(目标对象)*** 的状态发生改变,所有的依赖对象 ***(观察者对象)*** 都将得到通知。如果这样的依赖关系过于紧密,将使得软件不能很好的抵御变化

      使用面向对象技术,可以将这种依赖弱化,并形成一定稳定的依赖关系。从而实现软件体系结构的松耦合

例子

创建一个进度条的更新程序,程序的作用是将一个大文件进行分割

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
class MainForm : public Form{
TextBox* txtFilePath;
TextBox* textFileNumber;


public: Button_click(){
string filePath = txtFilePath->getText();
int number = atoi(textFileNumber->getText().c_str());

ProgessBar m_progressBar;

FileSplitter splitter(filePath,number,m_progressBar);


splitter.split()
}
}

class FileSplitter{
string m_filePath;
int m_fileNumber;
ProgessBar* m_progressBar;

public:
FileSplitter(const string& filePath,int fileNumber,ProgessBar* progressBar):
m_filePath(filePath),
m_fileNumber(fileNumber),
m_progressBar(progressBar){
}

void split(){
// 1.读取文件
// 2.分批次向小文件中写入
for(int i=0;i< m_fileNumber;i++){
//...
m_progressBar->setValue((i+1)/m_fileNumber)
}
}

}

问题

  • 违背设计的原则
    • 依赖倒置原则,
      • 高层模块不应该依赖底层模块,二者都应该依赖于抽象。
      • 抽象不应该依赖于实现细节,实现细节应该依赖抽象

直观改进

  • 应该依赖于实现的父类

    父类可能没有相应的更新方法

改进(通知单个对象)

  • 我们需要的是告诉控件需要发生变化。因此抽象为一个通知

  • cpp支持多继承,但不推荐。推荐一个主继承类,其他继承接口

    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
    58
    59
    60
    61
    62
    class IProcess{
    public:
    virtual void DoProgress(float val)=0;

    virtual ~IProcess();
    }

    class MainForm : public Form,public IProcess{
    TextBox* txtFilePath;
    TextBox* textFileNumber;


    public: Button_click(){
    string filePath = txtFilePath->getText();
    int number = atoi(textFileNumber->getText().c_str());

    // ProgessBar m_progressBar; //具体的通知控件
    ProcessBar* processBar; // 抽象通知机制
    FileSplitter splitter(filePath,number,this);


    splitter.split();
    }

    virtual void DoProgress(float val){
    processBar->setValue(val);
    }

    }

    class FileSplitter{
    string m_filePath;
    int m_fileNumber;
    IProcess* m_iProcess;

    public:
    FileSplitter(const string& filePath,int fileNumber,IProcess* iProcess):
    m_filePath(filePath),
    m_fileNumber(fileNumber),
    m_iProcess(iProcess){
    }

    void split(){
    // 1.读取文件
    // 2.分批次向小文件中写入
    for(int i=0;i< m_fileNumber;i++){
    //...
    if(m_progressBar != nullptr){
    onProgress((i+1)/m_fileNumber) //更新进度条
    }

    }
    }
    protected:
    void onProgress(float value){
    if(m_progressBar != nullptr){
    m_progressBar->DoProgress(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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

class IProcess{
public:
virtual void DoProgress(float val)=0;

virtual ~IProcess();
}

class MainForm : public Form,public IProcess{
TextBox* txtFilePath;
TextBox* textFileNumber;


public: Button_click(){
string filePath = txtFilePath->getText();
int number = atoi(textFileNumber->getText().c_str());

// ProgessBar m_progressBar; //具体的通知控件
ProcessBar* processBar; // 抽象通知机制
ConsoleNotifier console;
FileSplitter splitter(filePath,number);
splitter.add(this);
splitter.add(&console)


splitter.split();
}

virtual void DoProgress(float val){
processBar->setValue(val);
}

}
class ConsoleNotifier : public IProgress{
public:
virtual void DoProgress(float val){
cout<<".";
}
}

class FileSplitter{
string m_filePath;
int m_fileNumber;
List<IProcess*> m_iProcessList;

public:
FileSplitter(const string& filePath,int fileNumber,IProcess* iProcess):
m_filePath(filePath),
m_fileNumber(fileNumber){
}

void split(){
// 1.读取文件
// 2.分批次向小文件中写入
for(int i=0;i< m_fileNumber;i++){
//...
if(m_progressBar != nullptr){
onProgress((i+1)/m_fileNumber) //更新进度条
}

}
}

void add(IProgress* iProgress ){
m_iProcessList.add(iProgress);
}

void remove(IProgress* iProgress){
m_iProcessList.remove(iProgress);
}

protected:
void onProgress(float value){
auto ite = m_iProcessList.begin();
while(ite != m_iProcessList.end()){
(*ite)->DoProgress(value); // 更新进度条
ite++;
}
}

}

模式定义

定义对象间的一种 (一对多(变化)) 的依赖关系,以便当一个对象(Subject)的状态发生改变时,***(所有依赖于)*** 它的对象都能够得到通知

UML图

观察者模式UML图