システムアーキテクト 2013年 午前2 問04
問題文
デザインパターンの中のストラテジパターンを用いて、帳票出力のクラスを図のとおりに設計した。この帳票出カストラテジクラスの説明のうち、適切なものはどれか。

選択肢
ア:クライアントは、どの帳票出力ストラテジクラスがどのフォーマットに対応するかを意識せずに利用できる。
イ:新規フォーマット用のアルゴリズムの追加が容易である。(正解)
ウ:帳票出力ストラテジクラスの中で、どのフォーマットで帳票を出力するかの振分けを行っている。
エ:帳票出力のアルゴリズムは、コンテキストクラスの中に記述する
🔒 解説は解答すると表示されます
新フォーマット追加の容易性【午前2解説】
正解の理由
ストラテジパターンはアルゴリズム(ここでは帳票出力のフォーマットごとの処理)を「抽象インタフェース」と複数の「具象ストラテジ」クラスに分離します。コンテキストはその抽象インタフェースを通して処理を呼び出すため、既存のコンテキストや他のストラテジに手を加えずに新しいフォーマット用の具象ストラテジを追加できる点が利点です。したがって選択肢のうち イ(新規フォーマット用のアルゴリズムの追加が容易である)が設問意図に合致します。
解法ステップ
- 図から役割を対応させる:中央が抽象ストラテジ(帳票出力ストラテジ)、下が具象ストラテジ(PDF、HTML)。左上がコンテキスト。
- ストラテジパターンの本質を確認する:アルゴリズムの分離と切替、拡張の容易さ。
- 各選択肢をパターンの本質と照合する:アルゴリズムの追加(拡張性)を述べているものが最も一致する。
- 結論:拡張(新フォーマット追加)の容易さを示す選択肢を正答とする。
選択肢別の誤答解説
- ア: クライアントは、どの帳票出力ストラテジクラスがどのフォーマットに対応するかを意識せずに利用できる。
誤り(部分的に成り立つが不十分)── ストラテジパターンではコンテキストが抽象インタフェース経由でストラテジを利用するため、コンテキスト内部の実装は具象クラスを意識しません。しかし「クライアント」が誰かによって意味が変わります。クライアント(例えばアプリの設定処理やファクトリ)はどの具象ストラテジを選ぶかを決める必要がある場合があり、その段階では具象クラス(PDF用かHTML用か)を意識します。よって「全く意識しなくて良い」と断言するのは誤りで、設問が問う「設計の利点(拡張性)」と合致しないため不適切です。 - イ: 新規フォーマット用のアルゴリズムの追加が容易である。
正答(理由は上記「正解の理由」を参照)。新しい具象ストラテジを追加するだけで既存コードをほとんど変更せずに機能拡張できる点がポイントです。 - ウ: 帳票出力ストラテジクラスの中で、どのフォーマットで帳票を出力するかの振分けを行っている。
誤り── 具象ストラテジは単一のアルゴリズム(あるフォーマットの出力処理)を実装する役割であり、「振分け(選択)」は本来コンテキストやクライアント側の責務です。振分けを各ストラテジ内部に記述すると責務分離が崩れ、パターンの利点が失われます。 - エ: 帳票出力のアルゴリズムは、コンテキストクラスの中に記述する。
明確に誤り── これはストラテジパターンの対義的な設計です。アルゴリズムをコンテキストに直接書くと拡張時にコンテキストを修正する必要が生じ、オープン/クローズド原則に反します。ストラテジの目的はアルゴリズムを切り離すことにあります。
よくある誤解
- 「クライアントは具象ストラテジを全く知らない」は誤解:コンテキストは抽象で具象を気にしないが、具象選択はクライアントや設定部分が行うことが多い点を混同しやすい。
- 「ストラテジパターンは状態遷移と同じ」は誤解:Strategyはアルゴリズム切替、Stateはオブジェクトの状態に応じた振る舞いの変更で目的が異なる。見た目が似る場合もあるが責務が違う。
- 「戦略が多くなるとクラス爆発するからダメ」は部分真実:戦略はクラス数が増えるが、単一責務でテスト容易、拡張容易という利点とトレードオフであり、必要に応じてファクトリや設定で管理する。
補足コラム
ストラテジパターンは「オープン/クローズド原則(既存コードを変えずに拡張できる)」を実現しやすく、帳票出力のようにフォーマットが増える可能性がある領域に特に有効です。実装上のポイントは以下です。
- 抽象インタフェース(あるいは抽象クラス)を明確に定義する。
- コンテキストはインタフェースを通してストラテジを利用し、具象に依存しない。
- 具象ストラテジは副作用を持たない(副作用がある場合は責務を整理する)。
- 具象の選択は起動時設定、DI(依存性注入)、ファクトリなどで行うと保守性が上がる。
簡単なPython例(概念示すのみ):
from abc import ABC, abstractmethod
class ReportStrategy(ABC):
@abstractmethod
def render(self, data):
pass
class PdfReportStrategy(ReportStrategy):
def render(self, data):
return f"PDF: {data}"
class HtmlReportStrategy(ReportStrategy):
def render(self, data):
return f"<html>{data}</html>"
class ReportContext:
def __init__(self, strategy: ReportStrategy):
self._strategy = strategy
def output(self, data):
return self._strategy.render(data)
# 新フォーマット追加は新しいクラスを追加するだけ
class XmlReportStrategy(ReportStrategy):
def render(self, data):
return f"<xml>{data}</xml>"
FAQ
Q: ストラテジは誰が選ぶべきですか?
A: 通常はクライアントやコンフィグ/ファクトリが選択します。コンテキストは選ばれたストラテジを使うだけで、選択ロジックを持たせると責務が混在します。
A: 通常はクライアントやコンフィグ/ファクトリが選択します。コンテキストは選ばれたストラテジを使うだけで、選択ロジックを持たせると責務が混在します。
Q: StrategyとFactoryは同時に使える?
A: はい。Factoryで適切な具象ストラテジを生成し、コンテキストに渡すという組合せが一般的です。
A: はい。Factoryで適切な具象ストラテジを生成し、コンテキストに渡すという組合せが一般的です。
Q: 既存のコンテキストを変更せずにフォーマットを増やすには?
A: 具象ストラテジを新規に実装し、生成(ファクトリやDI構成)箇所で追加すれば、コンテキスト本体の修正は不要です。
A: 具象ストラテジを新規に実装し、生成(ファクトリやDI構成)箇所で追加すれば、コンテキスト本体の修正は不要です。
関連キーワード: ストラテジパターン、拡張性、コンテキスト、具象ストラテジ、オープン/クローズド原則、ポリモーフィズム、責務分離

\ せっかくなら /
システムアーキテクトを
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

