Strategyパターンは以前勉強したことがあるけど、もう一度。
つーか、最近似たようなのを実装した気がする…

目次

  1. 概要
  2. クラス図
  3. コード
    1. インターフェース
    2. 演奏クラス
    3. ピアノ(楽器)クラス
    4. メリット
    5. デメリット
  4. 参考サイト・文献

概要


Strategyパターンは条件によってアルゴリズムをまるごと交換できるようにします。
これによって、実行時に振る舞いを変更することができます。

クラス図


以下のコードサンプルと比べてちょっと省略してる。

コード


今回は入力した値によってピアノ演奏の強弱を変えます。

インターフェース

ピアノ演奏のメソッドを定義します。

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace Strategy
{
/// <summary>
/// 演奏のインターフェース
/// </summary>
public interface IPlay
{
/// <summary>
/// 演奏
/// </summary>
void Play();
}
}

演奏クラス

実際にどのような演奏(アルゴリズム)をするかを実装したクラスです。
今回は「pp/p/f/ff」の4つの強弱に応じて4つ作った。
なお、Pianoクラス(強弱)がPianoクラス(楽器)と紛らわしい…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
namespace Strategy.Dynamics
{
/// <summary>
/// インターフェースの実装クラス。
/// ピアニッシモのときの演奏を実装します。
/// </summary>
public class Pianissimo : IPlay
{
public void Play()
{

System.Console.WriteLine("チャーン....");
}
}
}

namespace Strategy.Dynamics
{
/// <summary>
/// インターフェースの実装クラス。
/// ピアノのとき(楽器のピアノじゃなくて強弱のピアノ)の演奏を実装します。
/// </summary>
public class Piano : IPlay
{
public void Play()
{

System.Console.WriteLine("ポロローン....");
}
}
}

namespace Strategy.Dynamics
{
/// <summary>
/// インターフェースの実装クラス。
/// フォルテのときの演奏を実装します。
/// </summary>
public class Forte : IPlay
{
public void Play()
{

System.Console.WriteLine("ジャーン!");
}
}
}

namespace Strategy.Dynamics
{
/// <summary>
/// インターフェースの実装クラス。
/// フォルティシモのときの演奏を実装します。
/// </summary>
public class Fortessimo : IPlay
{
public void Play()
{

System.Console.WriteLine("ジャジャーン!");
}
}
}

ピアノ(楽器)クラス

サンプルではよくContextとかClientとか書いてあるクラス。
入力値に応じて生成するクラス(アルゴリズム)を変更します。
各アルゴリズムのインスタンスを保有し(下記サンプルでは都度生成しているが)呼び出す。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
namespace Strategy
{
/// <summary>
/// ピアノクラス(強弱じゃなくて楽器のほうのピアノ)
/// </summary>
public class Piano
{
private static IPlay _currentPlay;

/// <summary>
/// 演奏します。
/// </summary>
/// <param name="dynamics">強弱</param>
public void Play(string dynamics)
{

switch (dynamics)
{
case "pp":
_currentPlay = new Dynamics.Pianissimo();
break;
case "p":
_currentPlay = new Dynamics.Piano();
break;
case "f":
_currentPlay = new Dynamics.Forte();
break;
case "ff":
_currentPlay = new Dynamics.Fortessimo();
break;
default: //他の強弱記号あるけど、めんどくさいので省略
break;
}
//実行はインターフェースを通じて行う。
_currentPlay.Play();
}
}
}

以上。
あとは実行あるのみ。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace Strategy
{
public class Program
{
static void Main(string[] args)
{

var dynamics = System.Console.ReadLine();

Piano _piano = new Piano();
//ピアノを演奏します。
_piano.Play(dynamics);

System.Console.ReadLine();
}
}
}

入力した値によって結果が変わります。(略)

メリット

  • 実行時に振る舞いを変更することができる。
  • アルゴリズムの追加が容易。
  • アルゴリズムをまるごと入れ替えることができる。
  • アルゴリズムの実行にインターフェースを使用しているので結びつきが緩やか。

デメリット

  • アルゴリズムが増えた場合に、管理が複雑になる。

参考サイト・文献


サルでもわかる 逆引きデザインパターン > 第2章 逆引きカタログ ロジック編 > Strategy (ストラテジ)
増補改訂版Java言語で学ぶデザインパターン入門
C#実践開発手法