经过一些研究,我似乎找不到一个简单的例子来解决我经常遇到的问题。
假设我要创建一个小应用程序,可以在其中创建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;
};
(想象一下,我有更多种类的形状:三角形,六边形,每次都有它们的proprers变量以及相关的getter和setter。我遇到的问题有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
和来实现getter / setter对ShapeManager
?我已经尝试使用模板,但是失败了。
我现在面临的问题是不是真的与形状,但具有不同的Job
小号的3D打印机(例如:PrintPatternInZoneJob
,TakePhotoOfZone
,等)AbstractJob
作为其基类。虚方法execute()
不是getPerimeter()
。我唯一需要使用具体用法的方法是填写工作所需的特定信息:
PrintPatternInZone
需要打印点列表,区域位置以及一些打印参数,例如温度TakePhotoOfZone
需要拍摄照片的区域,保存照片的路径,尺寸等...
当我打电话给时execute()
,乔布斯将使用他们所必须的特定信息来实现他们应该采取的行动。
我唯一需要使用作业的具体类型的时间是当我填写或显示这些信息时(如果TakePhotoOfZone
Job
选择a,将显示一个小部件,用于显示和修改区域,路径和尺寸参数)。
该Job
s的再投入的列表Job
,其采取的第一个作业S,执行它(通过调用AbstractJob::execute()
),则进入下一个,上和,直到列表的末尾。(这就是为什么我使用继承)。
为了存储不同类型的参数,我使用了JsonObject
:
优点:任何作业的结构相同,设置或读取参数时无需dynamic_cast
问题:无法存储指针(指向
Pattern
或Zone
)
您是否有更好的存储数据方式?
那么当我必须修改该类型的特定参数时,如何存储该类型Job
的具体类型呢?JobManager
只有一个清单AbstractJob*
。
changeValue(int shapeIndex, PropertyKey propkey, double numericalValue)
在哪里PropertyKey
可以是枚举或字符串,而“ Width”(表示对setter的调用将更新width的值)是允许的值之一。