- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在寻找维基百科风格的引用资料,以引用实际工作的轻量级发布-订阅机制的设计和实现。我会根据答案和评论以及我自己的研究更新问题。
我研究了我的书籍和网络,寻找使用 Python 和 Delphi 完成的发布/订阅工作,但对结果并不满意。这些设计依赖于函数签名或位图或插槽来过滤消息或决定应该将什么传递给谁,并且要么过于严格(绑定(bind)到消息服务器),要么过于混杂(每个人都可以订阅任何东西)。
我不想自己写。我想找到已经设计良好、经过辩论和现场验证的东西。
今天我在 Delphi Pascal 中实现了一个设计(因为 Delphi 是我首先需要的)。正如这个 API 所做的那样,根据参数类型进行分派(dispatch)并不是一个原始想法(它在 Design Patterns Visitor
模式中进行了解释),我想我以前见过类似的东西(但我不记得在哪里;Taligent?)。它的核心是订阅、过滤和调度是在类型系统之上。
unit JalSignals;
// A publish/subscribe mechanism.
// 1. Signal payloads are objects, and their class is their signal type.
// 2. Free is called on the payloads after they have been delivered.
// 3. Members subscribe by providing a callback method (of object).
// 4. Members may subscribe with the same method to different types of signals.
// 5. A member subscribes to a type, which means that all signals
// with payloads of that class or any of its subclasses will be delivered
// to the callback, with one important exception
// 6. A forum breaks the general class hierarchy into independent branches.
// A signal will not be delivered to members subscribed to classes that
// are not in the branch.
// 7. This is a GPL v3 design.
interface
uses
SysUtils;
type
TSignal = TObject;
TSignalType = TClass;
TSignalAction = (soGo, soStop);
TCallback = function(signal :TSignal) :TSignalAction of object;
procedure signal(payload: TSignal);
procedure subscribe( callback :TCallback; atype :TSignalType);
procedure unsubscribe(callback :TCallback; atype :TSignalType = nil); overload;
procedure unsubscribe(obj :TObject; atype :TSignalType = nil); overload;
procedure openForum( atype :TSignalType);
procedure closeForum(atype :TSignalType);
上面的“回调”就像 Python 中的绑定(bind)方法。
Delphi 实现的完整源代码是here :
这是Python中的实现。我更改了键名,因为 signal 和 message 已经重载了。与 Delphi 实现不同,结果(包括异常)被收集并返回到列表中的信号器。
"""
A publish/subscribe mechanism.
1. Signal payloads are objects, and their class is their signal type.
2. Free is called on the payloads after they have been delivered.
3. Members subscribe by providing a callback method (of object).
4. Members may subscribe with the same method to different types of signals.
5. A member subscribes to a type, which means that all signals
with payloads of that class or any of its subclasses will be delivered
to the callback, with one important exception:
6. A forum breaks the general class hierarchy into independent branches.
A signal will not be delivered to members subscribed to classes that
are not in the branch.
"""
__all__ = ['open_forum', 'close_forum', 'announce',
'subscribe', 'unsubscribe'
]
def _is_type(atype):
return issubclass(atype, object)
class Sub(object):
def __init__(self, callback, atype):
assert callable(callback)
assert issubclass(atype, object)
self.atype = atype
self.callback = callback
__forums = set()
__subscriptions = []
def open_forum(forum):
assert issubclass(forum, object)
__forums.add(forum)
def close_forum(forum):
__forums.remove(forum)
def subscribe(callback, atype):
__subscriptions.append(Sub(callback, atype))
def unsubscribe(callback, atype=None):
for i, sub in enumerate(__subscriptions):
if sub.callback is not callback:
continue
if atype is None or issubclass(sub.atype, atype):
del __subscriptions[i]
def _boundary(atype):
assert _is_type(atype)
lower = object
for f in __forums:
if (issubclass(atype, f)
and issubclass(f, lower)):
lower = f
return lower
def _receivers(news):
bound = _boundary(type(news))
for sub in __subscriptions:
if not isinstance(news, sub.atype):
continue
if not issubclass(sub.atype, bound):
continue
yield sub
def announce(news):
replies = []
for sub in _receivers(news):
try:
reply = sub.callback(news)
replies.append(reply)
except Exception as e:
replies.append(e)
return replies
if __name__ == '__main__':
i = 0
class A(object):
def __init__(self):
global i
self.msg = type(self).__name__ + str(i)
i += 1
class B(A): pass
class C(B): pass
assert _is_type(A)
assert _is_type(B)
assert _is_type(C)
assert issubclass(B, A)
assert issubclass(C, B)
def makeHandler(atype):
def handler(s):
assert isinstance(s, atype)
return 'handler' + atype.__name__ + ' got ' + s.msg
return handler
handleA = makeHandler(A)
handleB = makeHandler(B)
handleC = makeHandler(C)
def failer(s):
raise Exception, 'failed on' + s.msg
assert callable(handleA) and callable(handleB) and callable(handleC)
subscribe(handleA, A)
subscribe(handleB, B)
subscribe(handleC, C)
subscribe(failer, A)
assert _boundary(A) is object
assert _boundary(B) is object
assert _boundary(C) is object
print announce(A())
print announce(B())
print announce(C())
print
open_forum(B)
assert _boundary(A) is object
assert _boundary(B) is B
assert _boundary(C) is B
assert issubclass(B, B)
print announce(A())
print announce(B())
print announce(C())
print
close_forum(B)
print announce(A())
print announce(B())
print announce(C())
这些是我搜索的原因:
自己和别人找到的应该放这里
最佳答案
你应该试试 Enterprise Integration Patterns尽管它以进程间消息传递为中心,但它为发布-订阅提供了非常详细的处理。
关于python - 有用的发布-订阅语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4720763/
我正在尝试提升我的 javascript 编程技能(或者说我的编程技能时期 :)) 所以我试图理解一些语义: 第一行的“?”是什么意思?均值和“-distance”中的减号 第二行中的“+=”或“-=
我正在尝试在语义 UI 中执行复选框,但它不起作用,我无法弄清楚我做错了什么。 我包括jquery、semantic.min.js、checkbox.js 和semantic.min.css,然后我添
我正在构建一个 Spring 后端。我有一个 Controller ,它获取一个“搜索对象” - 一个具有 10 个字段的对象,其中只有一个应该被填充,所以搜索功能(我没有编写,但需要对其进行更改和重
我面临着编写更智能/高级的“相关内容”算法的挑战,并且不知道从哪里开始,所以我决定提出一个问题,是否有人会指出我正确的方向。 我们的数据库包含很多文章,到目前为止,我们使用关键字/标签查询了相关文章,
我正在尝试将通用字符串写入Rust中的数字函数,其中支持的类型为i16,i32,i64,u32,u64,f32和f64。 最初我有这个: fn str_to_num(s: &str, default_
假设我们在 hpp 文件中有一个带有唯一指针的简单结构: struct SomeType { SomeType() = default; ~SomeType(); st
这是同一预处理指令的多个问题。 1 - <> 还是 ""? 除了在 MSDN 中找到的信息: #include Directive (C-C++) 1.a:这两种符号有什么区别? 1.b:所有编译器都
所以基本上我有一个带有列表的简单系统,当我选择一个项目时,它会显示描述和绑定(bind)到该项目的图像。 项目:https://jsfiddle.net/jhnjcddh/2/ 问题是我需要在 JS
很抱歉问了一个愚蠢的问题,但有人能告诉我以下是什么意思吗 for ctype, (codename, name) in searched_perms: 我不明白括号里是怎么回事。 for ctype
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Why do all these crazy function pointer definitions al
我正在学习 HTML5,并获得了一个将 CSS Zen Gardens 转换为 HTML5 语义版本的项目。我已经能够轻松地转换其中的大部分内容,但是底部的链接/导航给我带来了一些问题。 转换此/处理
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improv
我一直在我的 emacs c/c++ 开发设置中试验 cedet 和语义,除了一个小细节外,我对它非常满意。 我使用 ede-cpp-root-project 创建一个项目,并给出我的项目的根目录以及
引用问题自http://www.garfieldtech.com/blog/put-up-with-put (这是针对 Drupal 开源项目的,有点元,因为这里没有代码): GET、HEAD 和 P
我有以下代码。 let v_blue = UIView() v_blue.backgroundColor = UIColor.blueColor() l
我目前正在 objc.io 上阅读优秀的 Advanced Swift 书籍,但遇到了一些我不明白的问题。 如果您在操场上运行以下代码,您会注意到在修改字典中包含的结构时,下标访问会生成一个副本,但随
谁能给我一个关于 Flutter 上下文中语义概念的清晰解释(或链接)(它实际上是什么,何时使用,更新...)? 我在谷歌上搜索了很多,但到目前为止还没有找到任何好的解释。 非常感谢, 最佳答案 Di
这是我的代码 Was this what you wanted? It's good to see you again.
我有一个侧边栏,其中包含应用程序的主导航。它还包含一个 button 触发侧边栏的打开/关闭。在语义方面,标记应该是什么样的? 我应该把侧边栏放在一边,然后只在周围设置导航吗主导航,不包括打开/关闭触
考虑下面这行 Lisp 代码: (some-function 7 8 | 9) ;; some comment. note the extra indentation 该点位于“8”和
我是一名优秀的程序员,十分优秀!