連載
|
|
|
■リファクタリング4:「ポリモーフィズムによる条件記述の置き換え(F)」によるStrategy階層の構築
条件記述に関する問題を解決するための最後のリファクタリングを行うことにしよう。これまでのリファクタリングはすべて、このリファクタリングを行うための準備と言っても過言ではない。
ここでは、条件記述を無くすために「ポリモーフィズムによる条件記述の置き換え(F)」を行う(なおポリモーフィズムとは、「派生クラスのインスタンスのオーバーライド・メソッドを、基本クラスの型を通じて呼び出すことで、処理内容を切り替える機能」のことだ。詳しくは「オブジェクト指向プログラミング超入門 第5回 継承を使わないとしても知っておくべきこと」を参照されたい)。
まずはTextFormatterクラスのFormatメソッドを仮想メソッドにして派生クラスでオーバーライドできるようにする。
|
|
派生クラスでオーバーライドできるようにしたTextFormatterクラスのFormatメソッド(C#) | |
■リファクタリング4の途中過程(プレーン・テキスト形式で「価値」の出力を行うStrategyの作成)
さらにTextFormatterクラスの派生クラスであるPlainTextFormatterクラスを作成して、基本クラスであるFormatメソッドをオーバーライドする。
|
|
新しく作成したPlainTextFormatterクラス(C#) | |
ここでもコンパイルとテストを実行して、きちんとテストがパスするかを確認しよう。
次にXpValuesクラスのCreatePlainTextFormatabletXpValuesメソッドでは、TextFormatterクラスではなく、PlainTextFormatterクラスのインスタンスを生成するように変更する。ここで、リファクタリング3で行った「Extract Parameter(K)」(パラメータの抽出)が活きてくる。
|
|
PlainTextFormatterオブジェクトを生成するようになったXpValuesクラスのCreatePlainTextFormatabletXpValuesメソッド(C#) | |
さらにTextFormatterクラスのFormatメソッドにあった、プレーン・テキスト出力部分のロジックを派生クラス(PlainTextFormatterクラス)のFormatメソッドへ移動する。
|
|
基本クラスのロジックが移動されたPlainTextFormatterクラスのFormatメソッド(C#) | |
派生クラスへ移動されたロジックは基本クラスのGetTitleForメソッドを呼び出すので、GetTitleForメソッドのアクセス修飾子をprotectedに変更する。
そして、ロジック移動後のFormatメソッドの条件分岐内では例外をスローするようにする。これは派生クラスでオーバーライドされているFormatメソッドが確実に呼び出されているかどうかを確認するためだ。
具体的なコードは次のとおりだ。
|
|
派生クラスへプレーン・テキスト出力のためのロジックが移動された後のTextFormatterクラス(C#) | |
コンパイルしてテストを実行すると、正常に実行されるはずだ。
■リファクタリング4の途中過程(HTML形式で「価値」の出力を行うStrategyの作成)
次にHtmlTextFormatterクラスを作成し、PlainTextFormatterクラスと同様の変更を行う。
具体的には、まずは下に示すHtmlTextFormatterクラスを作成しよう。なお、このクラスのFormatメソッドには、すでに基本クラス(TextFormatterクラス)からHTMLテキスト出力のロジックを移動している。
|
|
新しく作成したHtmlTextFormatterクラス(C#) | |
さらにXpValuesクラスのCreateHtmlTextFormatableXpValuesメソッドで先ほど作成したHtmlTextFormatterクラスのインスタンスを生成するように変更する。
|
|
HtmlTextFormatterオブジェクトを生成するようになったXpValuesクラスのCreateHtmlTextFormatableXpValuesメソッド(C#) | |
最後に、ロジック移動後のTextFormatterクラスのFormatメソッドは例外を投げるように変更しておこう。GetTitleForメソッドのアクセス修飾子は先ほど変更したので、今回は変更する必要はない。
|
|
派生クラスへHTMLテキスト出力のロジックが移動された後のTextFormatterクラス(C#) | |
以上のコードを再度コンパイルしてテストしてみよう。これも正常にコンパイルが終了し、テストも正しくパスするだろう。
■リファクタリング4の途中過程(Strategy 階層のトップに位置するクラスを抽象クラスにする)
ここまでくればTextFormatterクラスのFormatメソッド内の条件分岐は不要となる。またFormatメソッドは、派生クラス側ですべてオーバーライドされているので、TextFormatterクラスを抽象クラスに変え、Formatメソッドを抽象メソッドに変更する。
|
|
抽象クラスに変更したTextFormatter クラスと抽象メソッドに変更したFormatメソッド(C#) | |
コンパイルしてテストを実行する。問題なく実行できるはずだ。
■リファクタリング4の途中過程(出力形式のタイプの削除)
ここまでのリファクタリングの結果として、出力形式のタイプを保持するXpValuesクラスのフィールド変数formatTypeとFormatTypeプロパティは不要となるので削除する。
併せてプライベート・コンストラクタ、CreatePlainTextFormatableXpValuesメソッド、CreateHtmlTextFormatableXpValuesメソッドも変更する。
|
|
XpValuesクラスにおける不要となったFormatTypeプロパティの削除とそれに伴う変更(C#) | |
最後にもう一度プログラムをコンパイルし、テスト・コードをパスするか確認しておこう。
これで「ポリモーフィズムによる条件記述の置き換え(F)」が完了した。
●リファクタリングの結果
ここまでのリファクタリングによって作成および改善されたクラス構造を以下の図に示す。
リファクタリングの結果として導かれたStrategyパターンのクラス図 |
ここまでに行ったリファクタリングは「Replace Conditional Logic with Strategy(K)」(Strategyパターンによる条件ロジックの置き換え)と呼ばれているものだ。
その手順を簡単に振り返ってみよう。
1. Strategy 階層のトップに位置するクラス(TextFormatterクラス)の作成
2. 「メソッドの移動(F)」によるアルゴリズムの集合の分離
(XpValuesクラスのFromatメソッドのプレーン・テキスト形式の出力とHTML形式の出力のアルゴリズムをTextFormatterクラスへ移動)
3. 「Extract Parameter(K)」(パラメータの抽出)による各Strategyのインスタンス切り替えの準備
(XpValuesクラスのFormatメソッドで行っていたTextFormatterクラスのインスタンス生成をそのパラメータとして指定するようにメソッド・シグネチャを変更。TextFormatterクラスのインスタンス生成はXpValuesクラスのCreatePlainTextFormatXpValuesメソッドとCreateHtmlTextFormatXpValuesメソッドへ移動)
4. 「ポリモーフィズムによる条件記述の置き換え(F)」によるStrategy階層の構築
(PlainTextFormatterクラスとHtmlTextFormatterクラスを作成し、XpValuesクラスのFromatメソッドのプレーン・テキスト形式の出力のアルゴリズムはPlainTextFormatterクラスへ、HTML形式の出力のアルゴリズムはHtmlTextFormatterクラスへ移動して、TextFormatterクラスを両クラスの抽象クラスに変更する。これによりそれぞれのアルゴリズムがカプセル化されて交換可能となり、ポリモーフィズムの機能によってそれぞれのアルゴリズムを使い分けられるようになる)
メソッド内に条件記述があり、その分岐によって異なる振る舞いをするアルゴリズムが定義されているような場合には、このようなリファクタリングを実施する。これによってStrategyパターンが適用され、異なるアルゴリズムをそれぞれカプセル化して交換可能にすることができるのだ。
■
実はここまでのリファクタリングは、これから行おうとしているリファクタリングのための布石にすぎない。次回は引き続きリファクタリングを行って、さらなるパターンを導いていくことにしよう。
INDEX | ||
.NETで始めるデザインパターン | ||
第3回 リファクタリングにより導き出すStrategyパターン | ||
1.リファクタリング前の設計 | ||
2.リファクタリングによるStrategyパターンの適用 | ||
3.ポリモーフィズムによる条件記述の置き換え | ||
「.NETで始めるデザインパターン」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|