[英]How to design asynchronous wrapper returning values in Qt?
我在 Qt 中為外部可執行文件編寫了一個包裝類。 它有很多方法,其中大部分是:
在這種情況下,同步包裝器非常簡單:
class SyncWrapper {
public:
// Values are fetched *synchronously* in these methods
QString name() const;
QStringList files() const;
bool remove(const QString &file) const;
};
但是,我想讓這個包裝器異步,像這樣:
class AsyncWrapper {
Q_OBJECT
public:
// Values are fetched *asynchronously* in these methods
void name() const;
void files() const;
void remove(const QString &file) const;
signals:
// Values are returned via signals
void nameReady(const QString &name) const;
void filesReady(const QStringList &files) const;
void removeDone(bool success) const;
};
我不確定這種模式是否可以,因為有很多點與我有關:
我想出的其他一些想法:
QtConcurrent::run
。 不幸的是,這是一個非常龐大的解決方案。QFuture
對象。 同樣,這將需要在類之外使用QFutureWatcher
處理它們,這仍然非常龐大。在 Qt 中設計這種異步包裝器的正確方法是什么?
我認為命令模式可以在這里工作。
從抽象命令接口開始:
class Command : public QObject
{
Q_OBJECT
public:
virtual ~Command() = default;
virtual void execute() = 0;
signals:
void done(bool success) const;
};
子類並沒有那么復雜,只需給它們一些狀態並覆蓋execute
,例如
class NameCommand : public Command
{
QString _name;
public:
void execute() override
{
_name = ... //fetch name
emit done(true);
}
QString name() const { return _name; }
};
或者
class RemoveFileCommand : public Command
{
QString _filename;
public:
RemoveFileCommand(const QString filename) : _filename(filename){}
void execute() override
{
//remove _filename
emit done(true);
}
};
通過這種方式,您可以構建一組執行多種不同操作的對象,但您可以實現命令路由器並保持異步或不異步運行命令的機會:
class CommandRouter : public QObject
{
Q_OBJECT
public:
void run(Command * command, std::function<void(bool)> done, bool async = false)
{
connect(command, &Command::done, this, done, (async ? Qt::QueuedConnection : Qt::DirectConnection));
if(async)
{
QtConcurrent::run(command, &Command::execute);
}
else
{
command->execute();
}
}
};
所以你最終會得到類似的東西:
CommandRouter router;
RemoveFileCommand removecommand("somefile.tar.gz");
router.run(&removecommand, [](bool success) {
qDebug() << "REMOVE " << (success ? "SUCCESSFUL" : "FAILED");
}, true); //this will run asyncrounously
NameCommand namecommand;
router.run(&namecommand, [&namecommand](bool success) {
if(success)
{
qDebug() << "Name: " + namecommand.name();
}
else
{
qDebug() << "FETCH NAME FAILED";
}
}; //this will block
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.