`
qiezi
  • 浏览: 491358 次
  • 性别: 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实践设计模式的资料。
分享到:
评论

相关推荐

    C++ AOP编程理论

    C++平台的面向切面编程(aop)的理论知识。需要的直接拿去研究吧。

    aop:aspect

    NULL 博文链接:https://chenhongwei0924.iteye.com/blog/845772

    AOP 和 Aspect 注解切入 测试 Demo

    AOP 和 Aspect 注解切入 测试 Demo 1.ProxyFactory 基于 MethodBeforeAdvice、AfterReturningAdvice 利用 Spring Api 定义前、后置处理方法,并通过代理工厂类获取代理对象(代码或Xml配置实现) 2.ProxyFactoryBean...

    aop实战.rar

    aop实战

    整理的Spring AOP Aspect切入点语法

    整理的Spring AOP Aspect切入点语法,老师整理的,2018.08.01最新版

    aop,aspect相关jar包

    java开发过程中需要用到aspect,这时候需要用到相应的jar包。

    Spring AOP @Aspect 基本用法

    1、@Aspect放在类头上,把这个类作为一个切面。 2、 @Pointcut放在方法头上,定义一个可被别的方法引用的切入点表达式。 3、5种通知。 3.1、@Before,前置通知,放在方法头上。 3.2、@After,后置【finally】...

    Spring AOP实战 记录日志 下载可以直接使用

    也欢迎对AOP实战用法感兴趣的同学们加入。 使用场景及目标: 在生产环境中,通过巧妙的AOP机制,实现对日志的细致记录和处理。我们的目标是提高日志记录的效率和规范性,为监控和故障排查提供更为轻松便捷的工具。 ...

    在C++中运用AOP

    本文档记录了在c++语言中使用AOP的技术

    深入理解Android之AOP

    深入理解Android之AOP;深入理解Android之AOP;深入理解Android之AOP

    Java 经典设计模式讲解以及项目实战

    Java 经典设计模式讲解以及项目实战 设计模式简介:主要介绍各种设计模式的概念和运用场景等 设计模式综合运用:主要是笔者在实际工作中运用到的一些设计模式综合运用事例的提炼 Spring设计模式简介:主要是讲述...

    反射实现 AOP 动态代理模式(Spring AOP 的实现原理)

    AOP的意思就是面向切面编程。本文主要是通过梳理JDK中自带的反射机制,实现 AOP动态代理模式,这也是Spring AOP 的实现原理

    基于AOP策略模式的实现机制

    在当前软件需求越来越复杂的时代,策略模式作为23种经典的设计模式之一,它有着其重要的发挥舞台。本文首先将传统基于OOP策略模式的局限性进行分析说明,提出基本的策略模式以及“链式”策略模式基于AOP的具体实现,...

    springboot+aspect实现springaop拦截指定方法.zip

    项目中含有一整个springboot实现aop的功能,在拦截的方法形式上有两种一种是通过切点设置为拦截某个包路径下面的类中的所有方法;还有一种是基于某个自定义注解的.

    aop相关jar包括aspectjrt.jar,等

    aop相关jar下载

    Spring AOP配置实例

    Spring AOP配置的实例,最基本的Spring AOP配置

    Spring之AOP介绍

    对Spring框架中的AOP的介绍,能够全面了解Spring中AOP的功能和使用方法。

    用Java动态代理实现AOP

    目前整个开发社区对AOP(Aspect Oriented Programing)推崇备至,也涌现出大量支持AOP的优秀Framework,--Spring, JAC, Jboss AOP 等等。AOP似乎一时之间成了潮流。Java初学者不禁要发出感慨,OOP还没有学通呢,又来AOP...

    第四章:Spring AOP API 设计模式1

    第四章:Spring AOP 设计模式小马哥(mercyblitz)Spring AOP 设计模式抽象工厂模式(Abstract factory)实现构建器模式

Global site tag (gtag.js) - Google Analytics