몇 가지 연구를 한 후에 자주 발생하는 문제를 해결하는 간단한 예를 찾지 못하는 것 같습니다.
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
대해 getter / setter 커플 을 사용하지 않고 더 나은 디자인 이 있습니까? 이미 템플릿 을 사용하려고 했지만 실패했습니다 .
내가 직면하고있어 문제는 모양과하지만 정말 아닌 다른 Job
S : 3 차원 프린터 (예 PrintPatternInZoneJob
, TakePhotoOfZone
과 등) AbstractJob
자신의 기본 클래스로. 가상 방법은 execute()
아닙니다 getPerimeter()
. 구체적인 사용법을 사용해야하는 유일한 시간은 작업에 필요한 특정 정보를 채우는 것입니다 .
PrintPatternInZone
인쇄 할 포인트 목록, 구역 위치, 온도와 같은 일부 인쇄 매개 변수가 필요합니다.TakePhotoOfZone
사진을 찍을 영역, 사진이 저장되는 경로, 크기 등이 필요합니다.
그런 다음에 전화 execute()
하면 Jobs는 수행해야 할 작업을 실현하기 위해 필요한 특정 정보를 사용합니다.
구체적인 유형의 작업을 사용해야하는 경우에는 이러한 정보를 채우거나 표시 할 때뿐입니다 (a TakePhotoOfZone
Job
를 선택하면 영역, 경로 및 치수 매개 변수를 표시하고 수정하는 위젯이 표시됨).
Job
의는 다음의 목록에 넣고 Job
첫 번째 작업을 S (호출하여 실행 AbstractJob::execute()
)의 목록이 끝날 때까지 계속해서, 다음으로 이동합니다. (이것이 내가 상속을 사용하는 이유입니다).
다른 유형의 매개 변수를 저장하려면JsonObject
다음을 사용하십시오 .
장점 : 모든 작업에 동일한 구조, 매개 변수 설정 또는 읽을 때 dynamic_cast 없음
문제 : 포인터를 저장할 수 없습니다 (
Pattern
또는Zone
)
더 나은 데이터 저장 방법이 있습니까?
그런 다음 구체적인 유형을 저장하여Job
해당 유형의 특정 매개 변수를 수정해야 할 때 사용할 수 있습니까? JobManager
의 목록 만 있습니다 AbstractJob*
.
changeValue(int shapeIndex, PropertyKey propkey, double numericalValue)
곳에 PropertyKey
열거 나 문자열, 상기 허용 값 중 하나 인 (세터 호출 폭의 값을 업데이트하는 것을 의미하는) "폭"일 수있다.