ジェネリッククラスを使用して戦略パターンを適用した後、コードを削減する簡単な手順

このノートには、「戦略」パターンを適用した後に得られるコードを減らすためのいくつかのトリックが含まれています。 名前が示すように、それらはすべて何らかの形でジェネリック型の使用と関連しています。

これは記事の2番目のバージョンです。 最初の1つ( ジェネリッククラスを使用した「戦略」パターンの操作に対する一連の小さな改善と呼ばれる)は、ランダウとリフシッツの精神でいくつかの中間ステップが省略されたため、あまり成功しませんでした。 INC_Rに特別な感謝を表明します。INC_Rはコメントでこの簡単な事実を伝えてくれました。



1.魔術が作成されるクラスの階層

移動できる抽象Vehicleクラス(Moveメソッド)があるとします。 このクラスには、車、飛行機、人力車の3つの子孫があり、それぞれが独自の方法でこのメソッドを実装します。

abstract class Vehicle { abstract void Move(); } class Car : Vehicle { override void Move() { // burn fuel // spin wheel } } class Plane : Vehicle { override void Move() { // suck air // burn fuel // spew jetstream } } class Rickshaw : Vehicle { override void Move() { // do one step // beg white master for money } }
      
      







2.戦略の適用

新しい要件があり始めているとします:
  1. 新しいタイプの車両がまもなく登場することが明らかになりました。
  2. それらのいくつかは、同じ方法でMoveメソッドを実装します。 たとえば、機械と機関車の両方が燃料を燃やし、車輪を回します。
  3. 移動方法は変更できます。 たとえば、汽船は帆と蒸気の両方で牽引できます。
明らかに、移動を担当するコードを別のクラスのエンジンに割り当てる時間です。

 abstract class Vehicle { Engine Engine { get { return engine; } set { if (value != null) { engine = value; } else { throw new ArgumentNullException(); } } } private Engine engine; protected Vehicle(Engine engine) { Engine = engine; } public void Move() { engine.Work(); } } class Car : Vehicle { Car() : base(new InternalCombustionEngine()) { } } class Plane : Vehicle { Plane() : base(new JetEngine()) { } } class Rickshaw : Vehicle { Rickshaw() : base(new Slave()) { } } abstract class Engine { public abstract void Work(); } class InternalCombustionEngine : Engine { public override void Work() { // burn fuel // spin wheel } } class JetEngine : Engine { public override void Work() { // suck air // burn fuel // spew jetstream } } class Slave : Engine { public override void Work() { // do one step // beg white master for money } }
      
      







3.可能であればコードを短くします

運転中にエンジンを変更する必要がないことが車両の階層の一部で見つかった場合、いくつかの余分なコード行を節約するために、エンジンの種類によってそのような車両のクラスをパラメーター化するように手を引きます。 簡潔にするために、これらの変更はすでに宣言されているクラスにのみ影響するものと想定します。

 ... abstract class Vehicle<EngineT> : Vehicle where EngineT: Engine { protected Vehicle() : base(new EngineT()) { } } class Car : Vehicle<InternalCombustionEngine> { Car() : base(new InternalCombustionEngine()) { } } class Plane : Vehicle<JetEngine> { Plane() : base(new JetEngine()) { } } class Rickshaw : Vehicle<Slave> { Rickshaw() : base(new Slave()) { } } ...
      
      



エンジンクラスにパラメーターのないコンストラクターがある場合、これはEngineT型パラメーターに制約new()を追加することによっても使用する必要があります。

 ... abstract class Vehicle<EngineT> : Vehicle where EngineT: Engine, new() { protected Vehicle() : base(new EngineT()) { } } class Car : Vehicle<InternalCombustionEngine> { } class Plane : Vehicle<JetEngine> { } class Rickshaw : Vehicle<Slave> { } ...
      
      







4.多様性を追加する

この例では、3つのエンジン(はい、正確に3つのコピー、各タイプに1つ)のみがあり、多くの車両があり、それぞれが倉庫から稼働中のエンジンの1つを要求する必要があるとします。 これは、コード内で行われた変更の可視性の観点からの良い例ですが、実世界のロジックの嫌な観点:エンジンをあるマシンから別のマシンに再配置することは非常に疑わしい喜びです。 そして、そのようなアーキテクチャソリューションの結果は最も驚くべきものです。 そして、新しい要件に合わせてコードがどのように変化するかを以下に示します。

 ... abstract class Vehicle<EngineT> : Vehicle where EngineT : Engine { protected Vehicle() : base(Engine.GetFromWarehouse<EngineT>()) { } } ... abstract class Engine { abstract void Work(); private static readonly IDictionary<Type, Engine> warehouse = new Dictionary<Type, Engine> { { typeof(InternalCombustionEngine), new InternalCombustionEngine() }, { typeof(JetEngine), new JetEngine() }, { typeof(Slave), new Slave() }, }; static Engine GetFromWarehouse<EngineT>() where EngineT : Engine { return warehouse[typeof(EngineT)]; } } ...
      
      



soalexmnが正確に気付いたので、彼のおかげで、サービスロケーターパターンを見ました。 ご覧のとおり、森の中に行くほど戦略の残りは少なくなります。



5.複数の車で1つのエンジンを共有することは可能ですか?

はい、もちろんできます。 しかし、ここでは少し異なる例を使用する方が良いです。そうしないと、ファンタジーが爆発し、奴隷を想像しようとします。片足が自転車を踏み、もう片方が飛行機を蹴って飛ぶようにします。

 I 1 = new (); .(1); .(1); .(1);
      
      







これらのメモが誰にとっても有用であれば、私はうれしいです。



All Articles