これを1秒間考えてみましょう。私はあなたが2つのサブクラスを持っているだけではないので、これを一般化しようと思います。
最初に心に浮かぶのは、コードの複製、拡張性、親密性です。これらを拡張しましょう:
さらにクラスを追加したい場合は、可能な限り最小限の場所でコードを変更する必要があります。
intersect
操作が可換あるので、A
とB
と交差するためのコードがB
とA
と交差するので、それ自体が論外であるクラス内のロジックを維持するためのコードと同じ場所にする必要があります。
また、新しいクラスを追加すると、既存のクラスを変更する必要はなく、デリゲートクラスを拡張する必要があります(はい、ここにパターンがあります)。
これはあなたの現在の構造である、私は仮定(またはintersect
のための同様の、おそらく、戻り値の型が、今のために重要ではありません):
struct Primitive
{
virtual void intersect(Primitive* other) = 0;
};
struct Sphere : Primitive
{
virtual void intersect(Primitive* other)
};
struct Plane : Primitive
{
virtual void intersect(Primitive* other);
};
は、我々はすでに我々がPlane
内部の交差点ロジックを望んでいないことを決めましたまたはSphere
ので、私たちは新しいclass
を作成:
struct Intersect
{
static void intersect(const Sphere&, const Plane&);
//this again with the parameters inversed, which just takes this
static void intersect(const Sphere&, const Sphere&);
static void intersect(const Plane&, const Plane&);
};
これは、新しい機能を追加することがありますクラス、および新しいロジックです。たとえば、Line
クラスを追加する場合は、メソッドintersec(const Line&,...)
を追加するだけです。
新しいクラスを追加するときに、既存のコードを変更しないことを忘れないでください。したがって、交差関数内の型をチェックすることはできません。
私たちは、種類に応じて異なる動作をし、このための行動クラス(戦略パターン)を、作成することができ、私たちはその後拡張することができます。
struct IntersectBehavior
{
Primitive* object;
virtual void doIntersect(Primitive* other) = 0;
};
struct SphereIntersectBehavior : IntersectBehavior
{
virtual void doIntersect(Primitive* other)
{
//we already know object is a Sphere
Sphere& obj1 = (Sphere&)*object;
if (dynamic_cast<Sphere*>(other))
return Intersect::intersect(obj1, (Sphere&) *other);
if (dynamic_cast<Plane*>(other))
return Intersect::intersect(obj1, (Plane&) *other);
//finally, if no conditions were met, call intersect on other
return other->intersect(object);
}
};
そして、私たちが持っているだろう私たちのオリジナルの方法で:
を
struct Sphere : Primitive
{
virtual void intersect(Primitive* other)
{
IntersectBehavior* intersectBehavior = BehaviorFactory::getBehavior(this);
return intersectBehavior.doIntersect(other);
}
};
:
struct Sphere : Primitive
{
virtual void intersect(Primitive* other)
{
SphereIntersectBehavior intersectBehavior;
return intersectBehavior.doIntersect(other);
}
};
でもクリーンなデザインは、行動のうち抽象実際の型に、工場を実装することになります
であり、intersect
は仮想クラスである必要はありません。なぜなら、これはすべてのクラスでこれを行うためです。新しいクラスを追加するときは、この設計
- に既存のコードを変更する必要が従っていない場合は
- は
- は、それぞれの新しいタイプ
- のみ
IntersectBehavior
を延長する単一の場所での実装を持っています新しいタイプのためのIntersect
クラスの実装を提供する
そして、私はこれをさらに完成させることができると確信しています。
ポリモーフィズムが必要な場合は、なぜ静的タイプが必要でしょうか?インタフェースで基本クラスポインタを使用し、実行時に型を動的に把握できるようにします。それは、仮想メソッドの全体のポイントのようなものです。 – AJG85
バーチャルスタティックはどのように呼びますか? –
私は[http://stackoverflow.com/questions/325555/c-static-member-method-call-on-class-instance]や 'this'ポインタのようなインスタンスを通して呼び出しを行うことを考えていました、例えば[http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fcplr039.htm] – wsaleem