意图
它可将请求转换为一个包含与请求相关的所有信息的独立对象。该转换让你能根据不同的请求将方法参数化、延迟请求执行或将其放入队列中,且能实现可撤销操作。
例子
以下是 AWTK-MVVM 请求导航器打开指定的窗口的函数:
ret_t navigator_to(const char* target) {
ret_t ret = RET_OK;
navigator_request_t* req = NULL;
return_value_if_fail(target != NULL && navigator() != NULL, RET_BAD_PARAMS);
/* 根据字符串target创建对应命令 */
req = navigator_request_create(target, NULL);
return_value_if_fail(req != NULL, RET_OOM);
/* 处理请求 */
ret = navigator_handle_request(navigator(), req);
object_unref(OBJECT(req));
return ret;
}
ret_t navigator_handle_request(navigator_t* nav, navigator_request_t* req) {
navigator_handler_t* handler = NULL;
return_value_if_fail(nav != NULL && req != NULL, RET_BAD_PARAMS);
handler = navigator_find_handler(nav, req->target);
if (handler == NULL) {
handler = navigator_find_handler(nav, NAVIGATOR_DEFAULT_HANDLER);
}
if (handler == NULL) {
log_warn("not found %s\n", req->target);
}
return_value_if_fail(handler != NULL, RET_NOT_FOUND);
return navigator_handler_on_request(handler, req);
}
static ret_t navigator_handler_awtk_on_request(navigator_handler_t* handler,
navigator_request_t* req) {
/* 根据命令选择处理方式 */
if (tk_str_ieq(req->target, NAVIGATOR_REQ_CLOSE)) {
const char* name = object_get_prop_str(OBJECT(req->args), NAVIGATOR_ARG_NAME);
widget_t* win = widget_child(window_manager(), name);
return window_manager_close_window_force(window_manager(), win);
} else if (tk_str_ieq(req->target, NAVIGATOR_REQ_BACK)) {
return window_manager_back(window_manager());
} else if (tk_str_ieq(req->target, NAVIGATOR_REQ_HOME)) {
return window_manager_back_to_home(window_manager());
}
if (!(req->open_new)) {
widget_t* wm = window_manager();
widget_t* target_win = widget_child(wm, req->target);
if (target_win != NULL) {
widget_t* curr_win = window_manager_get_top_window(wm);
return window_manager_switch_to(wm, curr_win, target_win, req->close_current);
}
}
return awtk_open_window(req);
}
命令模式结构
小结
适合应用场景
-
需要通过操作来参数化对象。
-
需要将操作放入队列中、操作的执行或者远程执行操作(命令序列化(转字符串))。
-
需要实现操作回滚功能(实现已执行操作的历史记录功能:备份状态或执行反向操作)。
优点
-
单一职责原则,你可以解耦触发和执行操作的类。
-
开闭原则,你可以在不修改已有客户端代码的情况下在程序中创建新的命令。
-
你可以实现撤销和恢复功能。
-
你可以实现操作的延迟执行。
-
你可以将一组简单命令组合成一个复杂命令。
缺点
- 代码可能会变得更加复杂, 因为你在发送者和接收者之间增加了一个全新的层次。
参考
22种设计模式:refactoringguru.cn/design-patterns
AWTK-MVVM :github.com/zlgopen/awtk-mvvm
《设计模式:可复用面向对象软件的基础》