C++11 设计模式--模板方法模拟实现Java Spring AOP

目录

    • 一:背景
    • 二:具体实现
    • 三:应用

一:背景

当进行数据库更新的时候,有以下场景需要处理:
1:业务方法执行开始的时候,需要拿到数据库连接,然后开启事务
2:若业务在某个环节抛异常,为了数据库数据的而一致性,需要回滚事务。3:若业务执行无异常,需要提交事务
4:最后无论业务成功或者失败,都需要释放资源

对于这个业务场景,Java Spring框架的AOP可以很方便的对业务方法做拦截处理。Java动态代理也能很方便的实现该需求。而C++没有相对应的特性。本文模仿Java AOP,基于设计模式中的模板方法,实现对业务的切面处理。

二:具体实现

首先先封装一个异常类

class Exception : public std::runtime_error {
public:
    explicit Exception(const std::string &msg) : std::runtime_error(msg) {

    }
};

接着实现一个切面基类,该基类需要封装一个统一的操作流程,然后开放出对业务不同时机的操作接口,只要实现类实现了这些接口,就能在不同的时机做不同的事情。其中运用C++11的std::enable_if,巧用SFINAE原则,实现对invoke返回值为void非void两种情况的处理,有种模板返回值"重载"的感觉,具体实现如下

template<typename U>
class Aspect {
    U *u = nullptr;
public:
    explicit Aspect(U *u) : u(u) {}

    /**
     * 内部环绕,主要用于自动清理资源等
     */
    class InnerAround {
    private:
        Aspect *aspect = nullptr;
    public:
        explicit InnerAround(Aspect *aspect) : aspect(aspect) {
            aspect->before();
        }

        ~InnerAround() {
            if (aspect)
                aspect->afterReturning();
        }
    };

protected:
    /**
     * 紧接着在做完业务之后执行
     */
    virtual void after() {}

    /**
     * 在业务开始的时候执行
     */
    virtual void before() {}

    /**
     * 在业务抛异常的时候执行
     */
    virtual void afterThrowing() {}

    /**
     * 在业务返回的之前[包括抛异常]执行
     */
    virtual void afterReturning() {}

public:

    /**
     * 若返回值为void
     * @tparam Func
     * @tparam Args
     * @param t
     * @param args
     * @return
     */
    template<typename Func, typename ...Args>
    auto invoke(Func &&t, Args &&...args)
    -> typename std::enable_if<
            std::is_void<decltype((u->*t)(std::forward<Args>(args)...))>::value,
            void
    >::type {
        InnerAround around(this);//利用局部变量特性,离开作用域自动析构
        try {
            (u->*t)(std::forward<Args>(args)...);
            after();
        } catch (Exception &exception) {
            afterThrowing();
            //异常外抛
            throw exception;
        }
    }

    /**
     * 若返回值不为void
     * @tparam Func
     * @tparam Args
     * @param t
     * @param args
     * @return
     */
    template<typename Func, typename ...Args>
    auto invoke(Func &&t, Args &&...args)
    -> typename std::enable_if<
            !std::is_void<decltype((u->*t)(std::forward<Args>(args)...))>::value,
            decltype((u->*t)(std::forward<Args>(args)...))
    >::type {
        InnerAround around(this);//利用局部变量特性,离开作用域自动析构
        try {
            auto ret = (u->*t)(std::forward<Args>(args)...);
            after();
            return ret;
        } catch (Exception &exception) {
            afterThrowing();
            //异常外抛
            throw exception;
        }
    }
};

三:应用

首先做一个事务切面

/**
 * 事务切面
 * @tparam T
 */
template<typename T>
class TransactionAspect : public Aspect<T> {
public:
    explicit TransactionAspect(T *t) : Aspect<T>(t) {}

protected:
    void before() {
        //获取链接并开启事务
        std::cout << "... get a connection ... " << std::endl;
        std::cout << "... start transaction ... " << std::endl;
    }

    void afterThrowing() {
        //模拟抛异常,回滚事务
        std::cout << "... exception throw ... " << std::endl;
        std::cout << "... rollback ... " << std::endl;
    }

    void afterReturning() {
        //释放连接
        std::cout << "... release a connection ... " << std::endl;
    }

    void after() {
        //提交事务
        std::cout << "... commit ... " << std::endl;
    }
};

然后是我们的业务层逻辑

class MyService {
public:
    int insert(int i) {
        //......
        std::cout << "[--- " << "begin insert :  " << i << " ---]" << std::endl;
        return i + 12;
    }

    void update(int id, const std::string &msg) {
        //......
        std::cout << "[--- " << "begin update : " << msg << " id : " << id << " ---]" << std::endl;
        throw Exception("throw a exception...");
    }
};

main函数

int main() {

    MyService service;
    std::cout << "------------------------------------------------------------------" << std::endl;
    int id = TransactionAspect<MyService>(&service).invoke(&MyService::insert, 1);
    std::cout << "--- lastInsertId: " << id << std::endl;
    std::cout << "------------------------------------------------------------------" << std::endl;
    std::cout << std::endl;
    std::cout << "------------------------------------------------------------------" << std::endl;
    try {
        TransactionAspect<MyService>(&service).invoke(&MyService::update, 100, "hello world");
    } catch (Exception &exception) {
    }
    std::cout << "------------------------------------------------------------------" << std::endl;
    return 0;
}

执行结果如下

------------------------------------------------------------------
... get a connection ... 
... start transaction ... 
[--- begin insert :  1 ---]
... commit ... 
... release a connection ... 
--- lastInsertId: 13
------------------------------------------------------------------

------------------------------------------------------------------
... get a connection ... 
... start transaction ... 
[--- begin update : hello world id : 100 ---]
... exception throw ... 
... rollback ... 
... release a connection ... 
------------------------------------------------------------------

你可能感兴趣的:(Java,C++,c++,spring,java)