观察者模式的一种实现——Caller

  欢迎参与讨论,转载请注明出处。

前言

  在程序设计的时候,观察者模式是一种应用广泛的设计模式,它是一种模块间的通信方式,对于程序的解耦性有所帮助。本文便提供了一种实现思路,也即是说,你需要先去了解观察者模式才方便阅读本文。
  以下代码演示将使用Lua语言,接下来的内容对阅读者的Lua水平有一定的要求。如果你不知道在Lua中class的实现方式,可参考这篇文章

实现

  首先构造Caller的结构关系,如图所示:relationship

  由此可见,Caller包含一个结构体——Listener。接下来是代码实现:

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
-- Caller.lua
local Class = require("class")
local Caller = Class()
function Caller:Ctor()
self.listenerList = {}
end
function Caller:AddListener(obj, func)
table.insert(self.listenerList, {obj = obj, func = func}) -- Create Listener.
end
function Caller:DelListener(obj, func)
for n=#self.listenerList, 1, -1 do
if (self.listenerList[n].obj == obj and self.listenerList[n].func == func) then
table.remove(self.listenerList, n)
return true
end
end
return false
end
function Caller:Call(...)
for n=1, #self.listenerList do
self.listenerList[n].func(self.listenerList[n].obj, ...)
end
end
return Caller

应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- A.lua
local Class = require("class")
local Caller = require("caller")
local B = require("b")
local A = Class()
function A:Ctor()
self.caller = Caller.New()
self.b = B.New(self.caller)
self.value = 0
end
function A:SetValue(value)
self.value = value
self.caller:Call(value)
end
return A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- B.lua
local Class = require("class")
local B = Class()
function B:Ctor(caller)
caller:AddListener(self, self.Print)
end
function B:Print(...)
print(...)
end
return B

  如上所示,在调用A:SetValue(value)时会连带调用B:Print(…),如此只需要通过操作Caller就能达到不同对象之间通信的效果。并且也无须将业务写死在A:SetValue(value)中,业务将集中存放在Caller中。

疑难解答

  问:Caller的缺点是什么?
  答:Caller的缺点的很明显,需要将Caller对象直传到其他模块处,这样并不是很安全(别处也可以做Caller的一切行为)。当然这个问题也很好解决,只需要采用Event机制对其进行封装即可。代码如下:

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
-- A.lua
local Class = require("class")
local Caller = require("caller")
local B = require("b")
local A = Class()
function A:Ctor()
self.event = function(...) self:OnEvent(...) end
self.caller = Caller.New()
self.b = B.New()
self.value = 0
end
function A:SetValue(value)
self.value = value
self.caller:Call(value)
end
function A:OnEvent(type, ...)
if (type == "AddListener") then
return self.caller:AddListener(...)
end
return "No Event"
end
return A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- B.lua
local Class = require("class")
local B = Class()
function B:Ctor(upperEvent)
upperEvent("AddListener", self, self.Print)
end
function B:Print(...)
print(...)
end
return B

  问:Caller在功能上有何可改进之处?
  答:在实际开发中,Caller的需求数量一般不止一个,届时可以考虑用List或Map对Caller进行管理。也可以考虑直接让Caller具备管理多个ListenerList,代码如下:

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
-- Caller.lua
local Class = require("class")
local Caller = Class()
function Caller:Ctor()
self.listenerListMap = {}
end
function Caller:AddListener(type, obj, func)
if (not self.listenerListMap[type]) then
self.listenerListMap[type] = {}
end
table.insert(self.listenerListMap[type], {obj = obj, func = func}) -- Create Listener.
end
function Caller:DelListener(type, obj, func)
if (not self.listenerListMap[type]) then
return false
end
local listenerList = self.listenerListMap[type]
for n=#listenerList, 1, -1 do
if (listenerList[n].func == func and listenerList[n].obj == obj) then
table.remove(listenerList, n)
return true
end
end
return false
end
function Caller:Call(type, ...)
if (not self.listenerListMap[type]) then
return
end
local listenerList = self.listenerListMap[type]
for n=#listenerList, 1, -1 do
listenerList[n].func(listenerList[n].obj, ...)
end
end
return Caller

后记

  以上内容仅为提供一个思路,它或许并非最完善的,也不一定能适用于所有编程语言中,对此有所心得者,欢迎前来探讨,提供更佳的思路。