アプリ版:「スタンプのみでお礼する」機能のリリースについて

例えば図形クラスという親クラスがいて、その下に三角形、四角形、円形、楕円形、星型、等の具体的な子クラスがいるとします。今ファクトリーパターンで図形を生成しているのですが、それぞれの図形が持つ初期値をどう設定しようか迷っています。

例えば四角形はx, y, width, heightが必要ですが、円形ではcenterX, centerY, radiusが必要になります。今の私の設計では、それぞれのインタフェースを用意しているのですが、図形が増えるたびに、そのインタフェースが増え、ある図形専用の関数(下の例だとcreate)が増えてしまいます。

こういった場合にはどのように対処するのが良いのでしょうか?初期化のパラメタを抽象化すれば良いような気がしますが、具体的な解決策が思い浮かびません。

//!< main.cpp
enum ZUKEI {
SHIKAKU=0,
EN = 1.
SANKAKU = 2,

}

Zukei* sankaku = zukeiFactory.create(SHIKAKU, x, y, width, height);
Zukei* shikaku = zukeiFactory.create(EN, centerX, centerY, radius);

//!< ZukeiFactory.cpp

Zukei* ZukeiFactory::create(int zukeiId, int x, int y, int width, int height){
switch(zukeiId) {
case SHIKAKU:
return new ShikakuZukei(x, y, width, height);
case EN:
//???return new EnZukei();
}
}
Zukei* ZukeiFactory::create(int zukeiId, int centerX, int centerY, int radius) {
switch(zukeiId) {
case SHIKAKU:
//???return new ShikakuZukei();
case EN:
return new EnZukei(centerX, centerY, radius);
}
}

宜しくお願いします。

A 回答 (2件)

> 図形が増えるたびに、そのインタフェースが増え


そのためのファクトリーパターンでは?
まずは #1 の方のとおり、使用するクラスを整理することですね。三角形・星型→多角形など。
それと、動作を enum ZUKEI のパラメータで変えている意味がわからないので、メソッド名を createRectangle, createCircle などにすべきでしょう。
他に例えば、長方形と楕円から大きさパラメータをくくりだして size(int width, int height) のように factory の状態を変化させればいいかもしれません。

class ShapeFactory {
int x, y, centerx, centery, width, height;
public:
Shape *createRectangle();
Shape *createEllipse();
Shape *createCircle(int radius);
...
void size(int width, int height);
void pos(int x, int y);
void center(int x, int y);
...
};

使用例
Shape *rect = factory.pos(10,10).size(100,50).createRectangle();
Shape *ellipse = factory.center(50,50).size(50,30).createEllipse();
Shape *circle = factory.center(50,50).createCircle(50);
    • good
    • 0

> Zukei* sankaku = zukeiFactory.create(SHIKAKU, x, y, width, height);


> Zukei* shikaku = zukeiFactory.create(EN, centerX, centerY, radius);
変数名と作っている図形が異なっている件

……はおいといて、こんな感じかなぁ。
enum ParameterType {
POSITION,
RECT_SIZE,
RADIUS,
POSITIONS,
// ...
}
class Parameter {
public:
Parameter(ParameterType type) : type_(type) {};
virtual ~Parameter() = 0;

ParameterType getType() const {return type_;};

private:
ParameterType type_;
};

class Position : public Parameter {
public:
Position(int x, int y) : Parameter(POSITION), x_(x), y_(y) {};
~Position() {};

int getX() const {return x_;};
int getY() const {return y_;};

private:
int x_;
int y_;
};
// 以下、上記と同様に矩形サイズ、半径、点列(三角形とか星型で使うはず)クラスを作成
// 点列は個数を固定するより std::vector<Position> を使ったほうがいいかも

struct ParameterSercher {
ParameterSercher()
ParameterSercher(ParameterType type) : type_(type) {};

bool operator()(const Parameter* param)
{
return param->getType() == type_;
}

private:
ParameterType type_;
}

Zukei* ZukeiFactory::create(int zukeiId, const vector<Parameter*>& params)
{
switch(zukeiId) {
case SHIKAKU:
vector<Parameter>::const_iterator i_pos = find_if(params.begin(), params.end(), ParameterSercher(POSITION));
vector<Parameter>::const_iterator i_rect_size = find_if(params.begin(), params.end(), ParameterSercher(RECT_SIZE));
if (i_pos == params.end()) || (i_rect_size == params.end()) return NULL;
int x = dynamic_cast<Position*>(*i_pos)->getX();
int y = dynamic_cast<Position*>(*i_pos)->getY();
int width = dynamic_cast<RectSize*>(*i_rect_size)->getWidth();
int height = dynamic_cast<RectSize*>(*i_rect_size)->getHeight();
return new ShikakuZukei(x, y, width, height);
case EN:
// 以下、上記と同様
}
}

Position* sankaku_pos = new Position(x, y);
RectSize* sankaku_rect = new RectSize(width, height);
vaector<Parameter*> params;
params.push_back(sankaku_pos);
params.push_back(sankaku_rect);
Zukei* sankaku = zukeiFactory.create(SHIKAKU, params);
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!