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