C++实现观察者模式

所谓观察者模式,个人理解就是一对多的对象之间的关系,多个对象就是观察者,下面写一个项目中用到的类似于观察者模式。
1.写一个抽象的事件基类,暴露的函数写成虚函数,在继承该事件类中的子类中实现这些虚函数

#ifndef IEVENT_H
#define IEVENT_H
#include <QString>

class IEvent
{
public:
    virtual ~IEvent(){}
    virtual bool setCommand(QString cmd) = 0; //判断cmd 是否为 本对象的 执行命令

    // 返回 命令是否 成功执行
    //result  标记执行结果是否正确
    // discription 输出结果描述
    virtual bool exeCommand(bool &reslt, QString &discription) = 0;
};

#endif // IEVENT_H

2.继承抽象事件基类的观察者1:点击事件

#ifndef CLICKEVENT_H
#define CLICKEVENT_H
#include "IEvent.h"

class ClickEvent : public IEvent
{
private:
    const QString EVENT_NAME = "点击";
    QString command;

public:
    ClickEvent();
    //这两个函数必须是和继承的父类的暴露的虚函数同名同参数
    bool setCommand(QString cmd);
    bool exeCommand(bool &reslt, QString &discription);
};

#endif // CLICKEVENT_H
bool ClickEvent::setCommand(QString cmd)
{
    // cmd   格式为:“点击 CE”

    if(cmd.isEmpty())
        return false;

    QStringList list = cmd.split(QRegExp("\\s+"));
    if(list.size() == 2 && list.at(0) == EVENT_NAME)
    {
        this->command = cmd;
        return true;
    }
    else
    {
        return false;
    }

}

bool ClickEvent::exeCommand(bool &reslt, QString &discription)
{
    //需求 执行 点击 事件, 并将执行结果返回
    QStringList list = command.split(QRegExp("\\s+"));
    QString btnName = list.at(1);
    PIX pix;
    BaseInfo *bp = BaseInfo::GetInstance();
    if(bp->getButtonPix(btnName, pix))
    {
        int sx,sy; //  分辨率
        if(bp->getResolution(sx,sy))
        {
            mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, pix.x * 65535 / sx, pix.y * 65535 / sy,0,0);
            mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
            Sleep(100);
            mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);
            
            return true;
        }
        else
        {
            discription = "配置文件中,未找到屏幕分辨率信息";
            return false;
        }
    }
    else
    {
        discription = "   配置文件中,未找到 此按钮的 位置信息";
        return false;
    }
}

3.继承抽象事件基类的观察者2:判断事件

#ifndef JUDGEEVENT_H
#define JUDGEEVENT_H
#include "IEvent.h"

class JudgeEvent : public IEvent
{
private:
    const QString EVENT_NAME = "期望";
    QString command;
public:
    JudgeEvent();
    //这两个函数必须是和继承的父类的暴露的虚函数同名同参数
    bool setCommand(QString cmd);
    bool exeCommand(bool &reslt, QString &discription);
};

#endif // JUDGEEVENT_H
bool JudgeEvent::setCommand(QString cmd)
{
    // cmd   格式为:“期望 显示框 值 等于 1005.6”

    if(cmd.isEmpty())
        return false;

    QStringList list = cmd.split(QRegExp("\\s+"));
    if(list.size() == 5 && list.at(0) == EVENT_NAME)
    {
        this->command = cmd;
        return true;
    }
    else
    {
        return false;
    }
}

bool JudgeEvent::exeCommand(bool &reslt, QString &discription)
{
    //需求 执行 点击 事件, 并将执行结果返回
    QStringList list = command.split(QRegExp("\\s+"));
    QString btnName = list.at(BTN_NAME);
    double expectValue = list.at(EXPECT_VALUE).toDouble();
    AREA area;
    QString filePath = "C:\\Users\\cf\\Desktop\\Qt5screen.jpg";
    QString disc;
    double value;
    BaseInfo *bp = BaseInfo::GetInstance();
    cvIdentify* cv = cvIdentify::GetInstance();
    if(bp->getShowArea(btnName, area))
    {
        //截屏
        if(cv->getScreenshotPath(area,filePath,disc))
        {//数字识别
            if(cv->getNumberIdentify(filePath, value))
            {
                if (value == expectValue)
                {
                    qDebug() << "expect = "<< (QString::number(value, 10, 5));
                    discription = "执行结果与用例期望值一致的";
                    reslt = true;
                    return true;
                    
                }
                else
                {
                    qDebug() << "unexpect = " << (QString::number(value, 10, 5));
                    discription = "执行结果与用例期望值不一致的";
                    reslt = false;
                    return true;
                }

            }
            else
            {
                discription = "识别失败";
                return false;
            }
        }
        else
        {
            discription = "截取数字失败";
            return false;
        }

        //discription = "";
        //return true;
    }
    else
    {
        discription = "配置文件中,未找到此显示框的位置信息";
        return false;
    }
}

4.写一个将两个观察者类绑定到执行器类中

#ifndef EXECUTOR_H
#define EXECUTOR_H
#include <QList>
#include <QString>
#include "IEvent.h"

class Executor
{
private:
    QList<IEvent* > IEvents;

public:
    Executor();
    void attach(IEvent* ievent);
    void detach(IEvent* ievent);
    bool exeCmd(QString cmd, bool &rel, QString &des);
};

#endif // EXECUTOR_H
#include "executor.h"
#include <Windows.h>
Executor::Executor()
{

}

void Executor::attach(IEvent *ievent)
{
    IEvents.push_back(ievent);
}

void Executor::detach(IEvent *ievent)
{
    IEvents.removeOne(ievent);
}

// 返回 命令是否 成功执行
// cmd 要执行的 命令
// rel  标记执行结果是否正确
// dis 输出结果描述
bool Executor::exeCmd(QString cmd, bool &rel, QString &des)
{
    foreach(auto event , IEvents)
    {
        if(event->setCommand(cmd))
        {
            Sleep(500);
            return event->exeCommand(rel,des);
        }
    }

    // 没有找到对应 事件
   //des = " 未能找到 此命令的执行程序";
    return false;
}

5.程序运行时线程中的执行函数,实现了观察者模式

void executorThread::test(const QStringList& fileName, const QVector<QStandardItem*> m_box)
{
    //qDebug() << QString("my object thread id:") << QThread::currentThreadId();
	//注册执行器的事件对象
	if (!m_box.isEmpty())
	{//这里将两个观察者绑定到执行类,根据程序运行时观察者的不同,执行不同的操作
		Executor* exep = new Executor();
		exep->attach(new ClickEvent());
		exep->attach(new JudgeEvent());
        int executCount = 0;
        int passCount = 0;
        
		for (int i = 0; i < fileName.size(); ++i)
		{   
            QList<QPair<int, QString> > stepList;
            if (importCmdFromDat(fileName.at(i), stepList))
            {
                emit sig_showExample(stepList);

                if (m_box.at(i)->checkState())
                {
                    
                    bool eveOk; // 事件是否 正常执行
                    bool resOk = true; // 结果是否 正确
                    QString exeDis; // 结果的具体描述
                    foreach(auto step, stepList)
                    {   
                        QMutexLocker locker(&m_lock);

                        if (isStop)
                        {
                            return;
                        }
                        resOk = true;
                        exeDis.clear();
                        eveOk = exep->exeCmd(step.second, resOk, exeDis);
                        emit sig_showResult(stepList,step, eveOk,exeDis);
                        // 对执行结果 处理, 打印,   保存
                        // todo
                    }
                    executCount++;
                    if (resOk)
                    {
                        passCount++;
                    }
                    emit sig_identifyResult(passCount,executCount,i,resOk);
                    //isStop = true;
                }
            }
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值