■
http://d.hatena.ne.jp/lethevert/20060612/p2
なるほど。これがStrategyパターンか。って、前もそんな感じでVisitorパターンを教えていただいたような。
http://d.hatena.ne.jp/w_o/20060219#p1
なんか、最近教えてもらってばっかりで、なんだか、どうもありがとうございます。
というわけで、デザインパターンなんて単語覚えるだけなんだから、そのぐらい勉強しろよ…って感じだな。あー、デザインパターンだけは、試験があってもいいかもしれない。
いや、でも、SpaceShipの移動アルゴリズムをMoverで分けただけでは十分じゃないのだ。(実際には十分だけど)
前回も書いたとおり、これだと、「ある矩形の中を移動する」っていう汎用的に使えそうなアルゴリズムが親子関係があるクラスにしか使えない。
class Meteorite { public: float x; float y; class Mover { virtual move( Meteorite &m ) = 0; }; }; class SpaceShip { public: float x; float y; class Mover { virtual move( SpaceShip &s ) = 0; }; };
んが。これではよくない。↓んで、こう
class Actor { float x; float y; class Mover {virtual move( Actor &m ) = 0; }; } class Meteorite: public Actor { ... }; class SpaceShip: public Actor { };
これで十分、十分なんだ…けど、ここで、アーキテクチャ宇宙飛行士的な思考が頭をよぎる…「これでは、移動という汎用的なアルゴリズムが、Actorにしか使えない!移動アルゴリズムは移動できるオブジェクト全てに使えるべきだ!!移動というのがActorと結び付いてるのがふんがふんg…」
そんで、移動アルゴリズムと、移動するオブジェクトは、完全に分離されなければならなくなる。
class Meteorite{ float x; float y; float dx; float dy; }; class SpaceShip{ float x; float y; float dx; float dy; }; template<typename Obj> void move( Obj& ) { ... }
これで、移動というのは、「変更可能な(x,y)があって、それぞれ速度がある」オブジェクト全てに使えるようになる。
これで、安心…ではなく、まだ若干安心できない部分があって、「本当にxの速度はdxなのか?」とかいうの。現に、昨日は、idou_kyori_xってなってたし。
そこで、
template < typename Ret, typename T > Ret getMemberDX( T &obj ) { return obj.dx; } template < typename Ret, typename T > Ret getIdoukyoriDX( T &obj ) { return obj.idou_kyori_x(); } template<typename Obj,typename DXGetter> void move( Obj& o, DXGetter dx_getter ) { o.x += dx_getter(o); }
こうなって、ここらへんで、戻り値がテンプレートにできなくて終わる。終了条件は、「C++の限界」。
/* あー…これがコンパイルできない。 */ template< typename Ret, typename Arg > Ret ret_it( Arg a ) { return a; } int main(){ ret_it( 3); }
(これを見てたら、Dならもっと突っこんでいけるような気がした : ほんとうに範囲チェックがXだけでいいのか → 境界は数値だけでいいのか → 変更可能な値全てに適用できるアルゴリズムへ)。
話が逸れすぎ。もとの話がなんなのかはわからないところではあるけど。
で、話は変わって、「Javaでは書けない」とか、確かめもしないでうかつなことを書いたような気がしたけど、どうやらそうらしい。
class SpaceShip { float x; float y; float dx; float dy; } /* class Mover { public <Target> void move( Target t ) { t.x += t.dx; // 無理 } } */ class Mover { public <Target extends SpaceShip > void move( Target t ) { t.x += t.dx; } }
こう書くのと変わらない気が。
class Mover { public void move( SpaceShip t ) { t.x += t.dx; } }
Generics使えねー。コンテナ専用といったところか。
class Nanika { /* こう書く以外にどう使えと… */ public <T> T add( T t ) { Vector<T> v = new Vector<T>(); v.add( t ); return v.get(0); } }
もちろん、ここでは、「コンテナに使えたら十分でしょ」っていう風に切り返されたりするところなので、まあ、いいんだと思う。
あー、あと、関数型言語の多相関数でも親子関係の無いオブジェクトのメンバに直接アクセスするようなのは書けないのか。
f inc setter getter obj = setter x ( (getter x) + inc )
こういうのならいけるけど。
と、なると、C++のテンプレートは多相関数より偉い。Dのテンプレートはそれよりも偉い。
Generics(親子関係がいる) < poly func(アクセサがいる) < C++ template(名前があってればいい) < D template(名前があってればいい + α)
ん。発散しすぎ。何が言いたいんだ。結論を最初に決めてから書きましょう。
いや、何が言いたいかは最初から決まってたんだ。
「operator()を駆使するような奴は、頭悪いか変態かのどっちかなので近寄ってはいけない」