`
qiezi
  • 浏览: 500889 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

[C++之AOP]实战Aspect C++之观察者模式

    博客分类:
  • c++
阅读更多
Aspect C++支持“虚切面”,类似C++中的虚函数。方面可以继承,“派生方面”可以重写“基方面”的“虚切面”,类似C++中的类继承。

有了这个特性,就可以实现一些模式了,这里列出AOP中经典的观察者(Observer)模式[注]

[注]这个说法不太妥当,观察者模式是经典的设计模式,这里的意思是说AOP经典的观察者模式实现。

它的代码如下:

aspect ObserverPattern {
    
// 管理subjects和observers的数据结构
    
// TODO 
public:
    
// 角色接口
    struct ISubject {};
    
struct IObserver {
        
virtual void update(ISubject *= 0;
    };
    
// 在派生方面中被重写
    pointcut virtual observers () = 0;
    pointcut 
virtual subjects () = 0;
    
// subjectChange()匹配所有非const方法,但限定了subjects类
    pointcut virtual subjectChange () =
        execution(
" % ::%(" && !" % ::%() const")
        
&& within(subjects ());
    
// 为每个subject/observer类增加基类,并插入通知代码
    advice observers () : baseclass(IObserver );
    advice subjects () : baseclass(ISubject );
    advice subjectChange () : after() {
        ISubject 
* subject = tjp->that ();
        updateObservers (subject );
    }
    
// 具体操作
    void updateObservers (ISubject * sub ) {  }
    
void addObserver (ISubject * sub , IObserver * ob ) {  }
    
void remObserver (ISubject * sub , IObserver * ob ) {  }
};

其中“...” 部分是需要完成的C++实现代码,可以简单实现一个:
#ifndef __OBSERVER_PATTERN_AH__
#define __OBSERVER_PATTERN_AH__

#include 
<map>
#include 
<set>
using namespace std;

aspect ObserverPattern {
    
// 管理subjects和observers的数据结构
    struct ISubject;
    
struct IObserver;
    map 
< ISubject*set<IObserver*> > listeners;
public:
    
// 角色接口
    struct ISubject {};
    
struct IObserver {
        
virtual void update(ISubject *= 0;
    };
    
// 在派生方面中被重写
    pointcut virtual observers () = 0;
    pointcut 
virtual subjects () = 0;
    
// subjectChange()匹配所有非const方法
    pointcut virtual subjectChange () =
        execution(
" % ::%(" && !" % ::%() const")
        
&& within(subjects ());
    
// 为每个subject/observer类增加基类,并插入通知代码
    advice observers () : baseclass(IObserver );
    advice subjects () : baseclass(ISubject );
    advice subjectChange () : after() {
        ISubject 
* subject = tjp->that ();
        updateObservers (subject );
    }
    
// 具体操作
    void updateObservers (ISubject * sub ) {
        
const set<IObserver*>& observers = listeners[sub];
        
set<IObserver*>::const_iterator iter = observers.begin();
        
for (; iter != observers.end(); iter ++)
        {
            (
*iter)->update(sub);
        }
    }
    
void addObserver (ISubject * sub , IObserver * ob ) { listeners[sub].insert(ob); }
    
void removeObserver (ISubject * sub , IObserver * ob ) { listeners[sub].erase(ob); }
};

#endif // __OBSERVER_PATTERN_AH__

保存为ObserverPattern.ah供下面使用。

下面编写一个应用实例:

1、car.h

#ifndef __CAR_H__
#define __CAR_H__

#include 
<string>
using namespace std;

class Car
{
    
string name;
    
int x;
    
int y;
    
enum Direction{South, East, North, West};
    Direction direction;

    Car (
const Car&);
    Car
& operator = (const Car&);
public:
    Car (
const string& name);
    
void turnLeft ();
    
void turnRight ();
    
void forward (size_t step);

    
const string& getName() const;
    
int getX () const;
    
int getY () const;
    Direction getDirection () 
const;
};



#endif // __CAR_H__


2、car.cc

#include 
"car.h"
#include 
<cassert>

Car::Car (
const string& name_)
: name(name_), x(
0), y(0), direction(South)
{
}

void Car::turnLeft ()
{
    
if (direction == West)
        direction 
= South;
    
else
        direction 
= (Direction)(int(direction) + 1);
}

void Car::turnRight ()
{
    
if (direction == South)
        direction 
= West;
    
else
        direction 
= (Direction)(int(direction) - 1);
}

void Car::forward (size_t step)
{
    
switch (direction)
    {
    
case South:
        y 
+= step; break;
    
case East:
        x 
+= step; break;
    
case North:
        y 
-= step; break;
    
case West:
        x 
-= step; break;
    
default:
        assert (
!"Invalid direction");
    }
}

const string& Car::getName() const
{
    
return name;
}

int Car::getX() const
{
    
return x;
}

int Car::getY() const
{
    
return y;
}

Car::Direction Car::getDirection() 
const
{
    
return direction;
}

3、dummy.h(这个用来测试Aspect C++的匹配模式会不会混乱)
#ifndef __DUMMY_H__
#define __DUMMY_H__

class Dummy
{
public:
    
void test_non_const (){}
    
void test_const () const {}
};

#endif // __DUMMY_H__

4、main.cc
#include "car.h"
#include 
"dummy.h"

int main()
{
    Car car(
"No.1");
    car.turnLeft();
    car.forward(
3);
    car.turnLeft();
    car.forward(
9);
    car.turnRight();
    car.forward(
12);

    Car car1(
"No.2");
    car1.forward(
7);
    car1.turnLeft();
    car1.forward(
3);

    car.forward(
5);

    Dummy dummy;
    dummy.test_non_const();
    dummy.test_const();
    
    
return 0;
}

这个程序编译运行,没有任何输出。有时候为了监视对象的状态,可以在执行一个操作后加上一些打印状态的代码,当然这样比较繁琐;也可以在各个操作函数中加入这些代码,但修改已经写好的代码总是不太舒服。

下面先实现一个Car状态打印类:

5、car_logging.h
#ifndef __CAR_LOGGING__
#define __CAR_LOGGING__

#include 
"car.h"
#include 
<iostream>
using namespace std;

class CarLogging
{
public:
    
void printCarInfo (const Car& car)
    {
        
static const char* direction_str[] = {"South""East""North""West"};
        cout 
<< "Car name: " << car.getName()
            
<< ", direction: " << direction_str[int(car.getDirection())] 
            
<< ", x: " << car.getX() 
            
<< ", y: " << car.getY() 
            
<< endl;
    }
};

extern CarLogging g_carLogging;

#endif // __CAR_LOGGING__

6、car_logging.cc
#include "car_logging.h"

CarLogging g_carLogging;

7、CarLoggingObserver.ah
#ifndef __CAR_LOGGING_OBSERVER_AH__
#define __CAR_LOGGING_OBSERVER_AH__

#include 
"ObserverPattern.ah"
#include 
"car.h"
#include 
"car_logging.h"

aspect CarLoggingObserver : 
public ObserverPattern {
    
// 定义方面(ointcuts)
    pointcut subjects() = "Car";
    pointcut observers() 
= "CarLogging";
public:
    advice observers() :
    
void update( ObserverPattern::ISubject* sub ) {
        printCarInfo (
*(Car*)sub);
    }

    advice construction (classes(subjects())) : after()
    {
        addObserver(tjp
->that(), &g_carLogging);
    }

    advice destruction (classes(subjects())) : before()
    {
        removeObserver(tjp
->that(), &g_carLogging);
    }
};

#endif // __CAR_LOGGING_OBSERVER_AH__

这个方面重写了subjects以及observers切面,并定义了observers在update被调用时执行的操作,另外还在Car的构造函数和析构函数中添加了注册和注销代码。

运行ac++生成代码,编译并运行,结果如下:

这里演示的例子依旧选择了不影响原始程序的做法,网上很多资料都把这个模式和实现代码结合起来,由于Aspect C++编译速度还是很慢,所以选择“外挂”的方式,这样不需要这些方面时,直接编译C++代码即可。

关于Aspect C++以及AOP,还有许多话题,不过不打算再继续了,AOP是个广泛的议题,局限在某一实现上只会使我们眼界变窄。

AOP被称为设计模式最佳实践者,它当之无愧。网上还有很多AOP实践设计模式的资料。
分享到:
评论

相关推荐

    Pro Cryptography and Cryptanalysis with C++20

    5. **设计模式与软件工程**:虽然主要关注密码学,但书中也会涉及软件设计原则,如工厂模式、策略模式、观察者模式等,这些都是构建复杂系统时常用的设计模式。此外,还会讨论Spring框架中的IOC(Inversion of ...

    java面试总结(ssh)

    - **设计模式**:面试中可能考察对常用设计模式(如工厂模式、单例模式、观察者模式等)的理解和应用。 掌握以上知识点,并结合实际项目经验和问题解决能力,将有助于在Java面试中脱颖而出。同时,熟悉SSH框架的...

    Java 经典问答

    12. **设计模式**:单例、工厂、观察者、装饰器、代理等23种设计模式的应用场景和实现方式。 13. **Spring框架**:IoC(Inversion of Control)和AOP(Aspect Oriented Programming)的概念,依赖注入,Spring Boot...

    Android设计思想解读开源框架.pdf

    - **LiveData**:是一个观察者模式的实现,用于在ViewModel和Activity之间传递数据。 - **生命周期感知**:LiveData会根据观察者的生命周期自动回调观察者,确保数据在适当的时候被更新。 **8.2 Navigation如何解决...

    ssm入门级例子

    1. Spring框架:Spring是Java企业级应用的核心框架,它提供了依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented Programming, AOP)等功能。DI使得对象之间的依赖关系在运行时动态绑定,降低了...

    丛林杂物

    9. **设计模式**:"Jungled Jumble Master"的代码中可能会使用到各种设计模式,如单例、工厂、观察者等,这些都是解决常见问题的最佳实践。 10. **异常处理**:Java中的异常处理是程序健壮性的重要部分,理解何时抛...

    Java_Developer_B1

    14. **设计模式**:包括单例、工厂、观察者等,是解决常见编程问题的标准化解决方案。 15. **Maven或Gradle**:构建工具,用于管理项目依赖和构建流程。 16. **单元测试**:JUnit或其他测试框架的使用,确保代码...

Global site tag (gtag.js) - Google Analytics