<返回更多

C++ 如何装饰函数实现代码最大程度复用

2021-09-28    自由技艺
加入收藏

0 前言

Hello,大家好,欢迎来到『自由技艺』的 C++ 系列专题。代码重用,尽可能避免冗余代码是程序员的一项必备技能,今天就来给大家介绍其中一种:函数装饰器。在设计模式中,与它对应的是类的装饰器模式,但个人觉得很鸡肋,下回再说吧。

1 需求来源

现在假设有一个基础功能函数,但是呢,存在各种应用场景,每种场景都需要对这个函数小修小补、或增加一些定制化的功能。有几种处理方式呢?基类派生?函数重载?建造者模式?都不大合适,而函数装饰器就是一种可参考的手段。

void test(int a, int b) {
    std::cout << (a + b) << "n";
}
void do_previous_work() {
    std::cout << "do previous works" << "n";
}
void do_after_work() {
    std::cout << "do after works" << "n";
}

template<typename RET, typename... ARGS>
std::function<RET(ARGS... args)> decorator(RET(*p_func)(ARGS... args)) {
    return [&](ARGS... args) -> RET {
        do_previous_work();
        test(args...);
        (*p_func)(args...);
        do_after_work();
    };
    //没有捕获任何变量的Lambda表达式可以转换成与它的调用原型一致的函数指针
}

int main() {
    int a = 10;
    int b = 20;
    f = test;
    f(a, b);   // 第一次调用 f
    std::function<void(int, int)> f;
    f = decorator(test);
    f(a, b);   // 第二次调用 f
    return 0;
}

输出结果:

C++ 如何装饰函数实现代码最大程度复用

 

2 总结

上述代码中有一个基本函数 test,如果需要在 test 之前做某些事情(do_previous_work),在 test 之后也做一些事情(do_after_work),那么定义一个装饰器函数,把 test 封装下,再用函数对象接收就可以了。从结果上看,调用了 f 两次,却输出了不同的结果。如果再有其他需求,类似地再实现一个装饰器函数,同样用 f 接收,再调用,就可以了。

留个思考题,如果把装饰器函数写成如下形式:

template<typename RET, typename... ARGS>
std::function<RET(ARGS... args)> decorator(RET(*p_func)(ARGS... args)) {
    auto post = [&](ARGS... args) -> RET {
        do_previous_work();
        test(args...);
        (*p_func)(args...);
        do_after_work();
    };
    return post;
}

这种写法有什么问题吗?欢迎留言区讨论~

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>