Aspect oriented programming的技術基礎可以看這裡
我想這篇已經寫得很清楚了,有興趣的話繼續Google。
接著試著用C++來實做一些Complie time的AOP方式。
Decorator Pattern
可以試著在關新的函數前面,加上Before跟After。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| template <typename WrappedType> class BaseAspect { protected: WrappedType* m_wrappedPtr;
struct AfterWrapper { BaseAspect* m_derived; AfterWrapper(BaseAspect* derived) : m_derived(derived) {}; void operator()(WrappedType* p) { m_derived->After(p); } }; public: explicit BaseAspect(WrappedType* p) : m_wrappedPtr(p) {};
virtual void Before(WrappedType* p) { // Default does nothing };
virtual void After(WrappedType* p) { // Default does nothing }
std::shared_ptr<WrappedType> operator->() { Before(m_wrappedPtr); return std::shared_ptr<WrappedType>(m_wrappedPtr, AfterWrapper(this)); } }; template <template <typename> class Aspect, typename WrappedType> Aspect<WrappedType> MakeAspect(WrappedType* p) { return Aspect<WrappedType>(p); }
|
這邊的重點是在After
的實現,因為我們不能像Before的方式直接使用。所以需要使用Metadata存起來。當shared_ptr的scope結束之後,會呼叫自定義的Destructor functor,也就是上面的AfterWrapper
。進行後面的After工作。
這邊有個個範例程式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| template <typename WrappedType> class LoggingAspect : public BaseAspect <WrappedType> { public: LoggingAspect(WrappedType* p) : BaseAspect<WrappedType>(p) {}
void Before(WrappedType* p) { std::cout << "entering" << std::endl; }
void After(WrappedType* p) { std::cout << "exiting" << std::endl; } };
class X { public: void funcX() { std::cout << "it is a test" << std::endl; } };
std::shared_ptr<X> p(new X()); MakeAspect<LoggingAspect>(p.get())->funcX();
|
當然,你也可以用[CRTP](Curiously recurring template pattern)來取代原先的Dynamic Binding,不過CRTP我實在不常用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| template <typename WrappedType, typename DerivedAspect> class BaseAspect { protected: WrappedType* m_wrappedPtr;
DerivedAspect* GetDerived() { return static_cast<DerivedAspect*>(this); } struct AfterWrapper { DerivedAspect* m_derived; AfterWrapper(DerivedAspect* derived) : m_derived(derived) {}; void operator()(WrappedType* p) { m_derived->After(p); } }; public: explicit BaseAspect(WrappedType* p) : m_wrappedPtr(p) {};
void Before(WrappedType* p) { // Default does nothing };
void After(WrappedType* p) { // Default does nothing }
std::shared_ptr<WrappedType> operator->() { GetDerived()->Before(m_wrappedPtr); return std::shared_ptr<WrappedType>(m_wrappedPtr, AfterWrapper(GetDerived())); } };
template <typename WrappedType> class LoggingAspect : public BaseAspect <WrappedType, LoggingAspect<WrappedType>> { typedef BaseAspect <WrappedType, LoggingAspect<WrappedType>> BaseAspect; public: LoggingAspect(WrappedType* p) : BaseAspect(p) {}
void Before(WrappedType* p) { std::cout << "entering" << std::endl; }
void After(WrappedType* p) { std::cout << "exiting" << std::endl; }
};
|
Function / Bind / Variadic template
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| struct Aspect { template<typename Func> Aspect(const Func& f) : m_func(f) {
}
template<typename T> void Invoke(T&& value) { value.Before(); m_func(); value.After(); }
template<typename Head, typename... Tail> void Invoke(Head&& head, Tail&&... tail) { head.Before(); Invoke(std::forward<Tail>(tail)...); head.After(); }
private: std::function<void()> m_func; };
template<typename... AP> void Invoke(const std::function<void()>& f) { Aspect msp(f); msp.Invoke(AP()...); }
|
這個版本的本質在於m_func
,利用Variadic template將m_func的前後包裝起來。達到串連的效果。
不過這個版本也有他的問題,例如不能將物件傳入函數裡面(因為已經變成一個function)。