Before/After クラス

デザインパターンの一つに Before/After パターンというのがあるらしくて、これは Before 処理をしたら After 処理を必ず行うように保証するパターンらしい。


Java ならこんな風に書ける

public void func()
{
    hoge.before();
    try
    {
        doSomething();
    }
    finally
    {
        hoge.after();
    }
}

これなら doSomething で例外が発生しても必ず hoge.after が呼ばれる。


C++ ならこんな風になる。

void func()
{
    hoge.before();
    try
    {
        do_something();
    }
    catch (...)
    {
        hoge.after();
        throw;
    }
    hoge.after();
}

hoge.after を2箇所に書いているのが恐ろしくかっこ悪いのだけれども、finally 節が無いので仕方ない。


ただ、C++ の場合は例外が発生してもデストラクタは必ず呼ばれるので、必ずこういう処理を行うクラスは簡単に用意できる。

struct scoped_before_after
{
    Hoge& hoge_;
    scoped_before_after(Hoge& hoge)
        : hoge_(hoge) { hoge_.before(); }
    ~scoped_before_after() { hoge_.after(); }
};

void func()
{
    scoped_before_after lock(hoge);
    do_something();
}

何度も使うようなパターンであればこれでいいんだけど、一度しか使わないような Before/After ならわざわざ作るのはめんどい。
だからといって同じ文を2度書くのは嫌なので、こんなクラスを作ってみた。

#include <boost/function.hpp>

struct scoped_before_after
{
    boost::function0<void> after_;
    scoped_before_after(const boost::function0<void>& after)
        : after_(after) { }
    scoped_before_after(const boost::function0<void>& before, const boost::function0<void>& after)
        : after_(after) { before(); }
    ~scoped_before_after() { after_(); }
};

これはこんな風に使う。

#include <boost/lambda/lambda.hpp>
#include "scoped_before_after.h"

struct fuga
{
    int value_ = 0;

    void func()
    {
        using namespace boost::lambda;
        scoped_before_after(var(value_) += 1, var(value_) -= 1);
        do_something();
    }
};

このように、特にクラス化する必要すら感じられない Before/After 処理を書く場合は使えるかもしれない。