プラグインにその引数の型を心配させ、各型を GUI コントロールにマップする方法を知っている別のコンポーネントを用意することをお勧めします。
これはほぼ単純なモデル/ビューの分解であるため、よく理解されているイディオムのようです。
これで、型モデルを列挙することができます。または、おそらくより多くの OO Visitor パターンを使用することもできますが、基本的には、固定された実際には拡張できない型システムを前もって考え出すことになります。それで十分ですか?
おそらく、特定の引数の特定の派生型と Qt でのレンダリング方法の詳細の両方を知っている型になるでしょう。これは Qt シグナルを処理し、値を引数に戻します。
... dynamic_cast を試したり、enum などの識別コードを読み取ったりして、考えています。これらの代わりにビジター DP をどのように使用できるかはまだわかりません...
Visitor パターンはを回避するために特にdynamic_cast
使用されているため、ここで何が混乱しているのかわかりません。確かに を使用する事後バージョンがありますdynamic_cast
が、それは実装に隠されているため、とにかく通常のケースではありません。
具体的な例として、いくつかの引数の型を持つモデルを作成してみましょう。
struct ArgumentHandler; // visitor
class Argument { // base class for visitable concrete types
public:
virtual void visit(ArgumentHandler&) = 0;
};
// sample concrete types
class IntegerArgument: public Argument {
int value_;
public:
IntegerArgument(int value = 0) : value_(value) {}
void set(int v) { value_ = v; }
int get() const { return value_; }
virtual void visit(ArgumentHandler&);
};
class BoundedIntegerArgument: public IntegerArgument
{
int min_, max_;
public:
virtual void visit(ArgumentHandler&);
// etc...
};
訪問する具体的な型がいくつかあるので、抽象的なビジターを書くことができます
struct ArgumentHandler {
virtual ~ArgumentHandler() {}
virtual void handleInteger(IntegerArgument&);
virtual void handleBoundedInteger(BoundedIntegerArgument&);
// ...
};
具象型は次のように訪問を実装します。
void IntegerArgument::visit(ArgumentHandler& handler) {
hander.handleInteger(*this);
}
void BoundedIntegerArgument::visit(ArgumentHandler& handler) {
hander.handleBoundedInteger(*this);
}
これで、データ モデル タイプに関してのみ抽象プラグインを作成できます。GUI ツールキットについて何も知る必要はありません。今のところ、その引数を照会する方法を提供しているとしましょう (各具体的なサブタイプには set/get メソッドが必要であることに注意してください)
class PluginBase
{
public:
virtual int arg_count() const = 0;
virtual Argument& arg(int n) = 0;
};
最後に、抽象プラグインにその引数を問い合わせる方法、各具体的な引数の型を表示する方法、および入力を処理する方法を知っている View をスケッチできます。
// concrete renderer
class QtView: public ArgumentHandler
{
struct Control {};
struct IntegerSpinBox: public Control {
QSpinBox control_;
IntegerArgument &model_;
};
struct IntegerSlider: public Control {
QSlider control_;
BoundedIntegerArgument &model_;
};
std::vector<std::unique_ptr<Control>> controls_;
public:
// these overloads know how to render each argument type
virtual void handleInteger(IntegerArgument &arg) {
controls_.push_back(new IntegerSpinBox(arg));
}
virtual void handleBoundedInteger(BoundedIntegerArgument &arg) {
controls_.push_back(new IntegerSlider(arg));
}
// and this is how we invoke them:
explicit QtView(PluginBase &plugin) {
for (int i=0; i < plugin.arg_count(); ++i) {
plugin.arg(i).visit(*this);
}
}
};
すべての仮想デストラクタ、Qt シグナル処理などを省略しました。QtView::IntegerSpinBox
しかし、うまくいけば、オブジェクトがvalueChanged
そのキャプティブ スピンボックス ウィジェットからのシグナルをどのように処理し、model_.set()
それをプラグインにプッシュするために呼び出すことができるかがわかります。