Провівши деякі дослідження, я не можу знайти простий приклад вирішення проблеми, з якою я стикаюся часто.
Скажімо, я хочу створити невелику програму, де я можу створювати Squares, Circles та інші фігури, відображати їх на екрані, змінювати їх властивості після їх вибору, а потім обчислювати всі їхні периметри.
Я б робив клас моделі так:
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;
};
.
Тепер у мене 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вибрано "А", буде показаний віджет, який відображає та змінює параметри зони, шляху та розмірів).
Потім Jobs вносяться до списку Jobs, який приймає перше завдання, виконує його (зателефонувавши AbstractJob::execute()), переходячи до наступного, увімкнення та продовження до кінця списку. (Ось чому я використовую спадщину).
Для зберігання різних типів параметрів я використовую JsonObject:
Переваги: однакова структура для будь-якої роботи, відсутність динамічного_видання під час встановлення чи зчитування параметрів
проблема: не можна зберігати покажчики (до
PatternабоZone)
Ви вважаєте, існує кращий спосіб зберігання даних?
Тоді як би ви зберігали конкретний тип для того,Job щоб використовувати його, коли мені доведеться змінювати конкретні параметри цього типу? JobManagerмає лише список AbstractJob*.
changeValue(int shapeIndex, PropertyKey propkey, double numericalValue)де PropertyKeyможе бути перерахунок або рядок, а "Ширина" (що означає, що виклик сеттера оновить значення ширини) є одним із дозволених значень.