C#でGoFのデザインパターン~Strategyパターン編~
2019-10-30
azblob://2022/11/11/eyecatch/2019-10-30-strategypattern-000.jpg

はじめに

以前の記事で、Stateパターンをご紹介しました。

デザインパターンについて学習していると、似たようなものに出くわすことがあります。

そうすると、以前に学習したものがどのような概念だったか自分でも怪しくなってくることもあります。

StateパターンとStrategyパターンはまさにそうで、Strategyパターンについて復習していると以前書いたStateパターンのサンプルが正確ではないことに今更ながら気づいたので、この記事を書きながらStateパターンの記事を修正したりしています。

今回は、そんなStrategyパターンの話になります。

Strategyパターンとは

Strategyパターンは、場面によって行いたい処理を分けたい場合に、それらの処理を外部にカプセル化することで必要な場面で必要な処理を使い分けられるようにするためのデザインパターンです。

処理を行う部分とその処理を利用する部分を分けているので、より柔軟に変更を加えることができるようになります。

今回の記事では、C#を用いてStrategyパターンを実装する方法を解説していきたいと思います。

Strategyパターン実装

まずは.NET Coreのコンソールアプリケーションでプロジェクトを作成します。

そうしたら、Strategyという振舞いを規定するインターフェースを作成します。

interface IStrategy
{
    void Strategy();
}

次に、そのインターフェースを継承し、振舞いの中身を実装するクラスを作成します。

class Strategy1 : IStrategy
{
    public void Strategy()
    {
        Console.WriteLine("Strategy1が実行されました");
    }
}

同じ振舞いで、中身の違う実装をする別のクラスを作成します。

出力する文字列を変えることで、別のStrategyであることを示しています。

class Strategy2 : IStrategy
{
    public void Strategy()
    {
        Console.WriteLine("Strategy2が実行されました");
    }
}

次に、これらのStrategyを使い分ける本体のクラスを実装します。

Stateパターンと同じように、引数に組み替えるためのStrategyを受け入れ、それを実行する部分とインスタンス化後にStrategyの組み換えを行うメソッドを作成します。

class Strategist
{
    private IStrategy _strategy;
    public Strategist(IStrategy strategy)
    {
        _strategy = strategy;
    }

    public void ExcuteStrategy()
    {
        Console.WriteLine("_strategyで実装されているStrategyを実行します");
        _strategy.Strategy();
    }

    public void ChangeStrategy(IStrategy strategy)
    {
        Console.WriteLine("Strategyを変更しています...");
        _strategy = strategy;
    }
}

最後に、これらを呼び出すコードをProgram.csに記述します。

まずはStrategy1を引数にしてStrategistをインスタンス化して実行し、その後でStrategy2に組み替えて実行しています。

class Program
{
    static void Main(string[] args)
    {
        var strategist = new Strategist(new Strategy1());
        strategist.ExcuteStrategy();
        strategist.ChangeStrategy(new Strategy2());
        strategist.ExcuteStrategy();
    }
}

ここまでの実装が成功していれば、


_strategyで実装されているStrategyを実行します
Strategy1が実行されました
Strategyを変更しています…
_strategyで実装されているStrategyを実行します
Strategy2が実行されました

という文字列が出力されるはずです!

Stateパターンとの違いは?

以前のStateパターンの記事を見た後にこの記事を読むと、StrategyパターンとStateパターンの違いがよくわからなくなるかもしれません。

どちらもクラスのインスタンス化をする際に、同じインターフェースを継承したインスタンスを引数にとることでそのクラスの振る舞いを変え、また、必要に応じてインスタンスを取り換えることで任意に状態やStrategyを変更しています。

これだけだとどちらも似たようなことをしていると感じますが、違いはStateパターンではその状態を示すクラスの中で状態を持つクラスの状態を変更するという点にあります。

つまり、Stateパターンの場合は外部からStateを変更するコードを追加で書かなくとも、その状態での処理を実行した際に処理の遷移まで行うことができます。
Strategyパターンにおいては「自由にStrategyを組み替えることができる」という点を主眼に置いているのに比べ、Stateパターンでは「Stateが自動的に遷移される」という点が主眼になっています。

これらの特徴をとらえて、必要な場所で必要なパターンを使い分けられるようになりましょう!

おわりに

今回は、C#を用いてStrategyパターンを実装する方法を示し、ついでにStateパターンとの違いについて説明しました。

パターンごとに解決しようとしている課題や目的は異なります。

これらを見極めて、様々なパターンを使いこなせるようになることを目指しましょう。