いくつかの調査を行った後、私が頻繁に遭遇する問題を解決する簡単な例を見つけることができないようです。
Square
s、Circle
s、およびその他の形状を作成し、画面に表示し、それらを選択した後でそれらのプロパティを変更して、すべての周囲を計算できる小さなアプリケーションを作成したいとします。
私はこのようなモデルクラスを行います:
class AbstractShape
{
public :
typedef enum{
SQUARE = 0,
CIRCLE,
} SHAPE_TYPE;
AbstractShape(SHAPE_TYPE type):m_type(type){}
virtual ~AbstractShape();
virtual float computePerimeter() const = 0;
SHAPE_TYPE getType() const{return m_type;}
protected :
const SHAPE_TYPE m_type;
};
class Square : public AbstractShape
{
public:
Square():AbstractShape(SQUARE){}
~Square();
void setWidth(float w){m_width = w;}
float getWidth() const{return m_width;}
float computePerimeter() const{
return m_width*4;
}
private :
float m_width;
};
class Circle : public AbstractShape
{
public:
Circle():AbstractShape(CIRCLE){}
~Circle();
void setRadius(float w){m_radius = w;}
float getRadius() const{return m_radius;}
float computePerimeter() const{
return 2*M_PI*m_radius;
}
private :
float m_radius;
};
(三角形、六角形、形状変数のプロパティと関連するゲッターとセッターが増えるたびに、形状のクラスが増えると想像してください。直面した問題には8つのサブクラスがありましたが、例のために2で停止しました)
これShapeManager
で、すべてのシェイプをインスタンス化して配列に格納しました。
class ShapeManager
{
public:
ShapeManager();
~ShapeManager();
void addShape(AbstractShape* shape){
m_shapes.push_back(shape);
}
float computeShapePerimeter(int shapeIndex){
return m_shapes[shapeIndex]->computePerimeter();
}
private :
std::vector<AbstractShape*> m_shapes;
};
最後に、各タイプの形状の各パラメーターを変更するためのスピンボックス付きのビューがあります。たとえば、画面で四角形を選択すると、パラメーターウィジェットにはにSquare
関連するパラメーターのみが表示され(のおかげでAbstractShape::getType()
)、四角形の幅を変更するように提案されます。これを行うには、で幅を変更できる関数が必要です。ShapeManager
これが私が行う方法です。
void ShapeManager::changeSquareWidth(int shapeIndex, float width){
Square* square = dynamic_cast<Square*>(m_shapes[shapeIndex]);
assert(square);
square->setWidth(width);
}
私が持つ可能性のあるサブクラス変数ごとにを使用しdynamic_cast
てゲッター/セッターのカップルを実装することを回避するより良いデザインはありShapeManager
ますか?私はすでにテンプレートを使用しようとしましたが、失敗しました。
私が直面してる問題がシェイプではなくて、実際にはない別のJob
S:3Dプリンタ用(EX PrintPatternInZoneJob
、TakePhotoOfZone
との、など)AbstractJob
彼らの基本クラスとして。仮想メソッドはexecute()
ありませんgetPerimeter()
。具体的な使用法を使用する必要があるのは、ジョブが必要とする特定の情報を入力するときだけです。
PrintPatternInZone
印刷するポイントのリスト、ゾーンの位置、温度などのいくつかの印刷パラメーターが必要ですTakePhotoOfZone
写真に取り込むゾーン、写真が保存されるパス、寸法などが必要です...
次にを呼び出すexecute()
と、ジョブは、実行する必要があるアクションを実現するために必要な特定の情報を使用します。
ジョブの具象タイプを使用する必要があるのは、これらの情報を入力または表示するときのみです(a TakePhotoOfZone
Job
が選択されている場合、ゾーン、パス、および寸法パラメーターを表示および変更するウィジェットが表示されます)。
次に、Job
sはJob
、最初のジョブを実行するsのリストに入れられ、(を呼び出すことによってAbstractJob::execute()
)それを実行し、次のジョブに進み、リストの最後まで続きます。(これが継承を使用する理由です)。
さまざまなタイプのパラメータを保存するには、JsonObject
次のように使用します。
利点:どのジョブでも同じ構造、パラメーターの設定または読み取り時にdynamic_castなし
問題:(
Pattern
またはへのZone
)ポインタを格納できません
データを保存するより良い方法があると思いますか?
次に、そのタイプの特定のパラメータを変更する必要があるときに、それを使用するために具体的なタイプをどのように保存しJob
ますか?JobManager
のリストしかありませんAbstractJob*
。
changeValue(int shapeIndex, PropertyKey propkey, double numericalValue)
ここでPropertyKey
列挙または文字列、及び許容値のいずれか一つである(セッターへの呼び出しが幅の値を更新することを意味する)「幅」とすることができます。