練習課題
概要
本課題では、「単一クラスに複数の責務が集中している状態(God Object)」に起因する設計上の問題点を整理し、
適切な責務分割およびデザインパターンの適用による改善案を検討する。
課題コード
以下のコードは、ブログ投稿に関する処理を一手に引き受けている PostManager
クラスの実装例である。
このコードを題材に、構造上の問題とその改善方法について考察すること。
- TypeScript
- PHP
- Python
// PostManager クラスが責務過多
class PostManager {
private posts: { title: string; content: string }[] = [];
private authorEmail: string = "";
setAuthor(email: string) {
this.authorEmail = email;
}
createPost(title: string, content: string) {
this.posts.push({ title, content });
}
publishAll() {
for (const post of this.posts) {
// 1. データベース保存(仮)
console.log(`保存: ${post.title}`);
// 2. 通知送信
console.log(`通知を ${this.authorEmail} に送信`);
// 3. ログ出力
console.log(`ログ: ${post.title} を公開`);
}
}
}
<?php
class PostManager {
private array $posts = [];
private string $authorEmail = "";
public function setAuthor(string $email): void {
$this->authorEmail = $email;
}
public function createPost(string $title, string $content): void {
$this->posts[] = ['title' => $title, 'content' => $content];
}
public function publishAll(): void {
foreach ($this->posts as $post) {
// 1. データ保存
echo "保存: {$post['title']}\n";
// 2. 通知送信
echo "通知を {$this->authorEmail} に送信\n";
// 3. ログ
echo "ログ: {$post['title']} を公開\n";
}
}
}
class PostManager:
def __init__(self):
self.posts = []
self.author_email = ""
def set_author(self, email: str):
self.author_email = email
def create_post(self, title: str, content: str):
self.posts.append({"title": title, "content": content})
def publish_all(self):
for post in self.posts:
# 1. データ保存
print(f"保存: {post['title']}")
# 2. 通知送信
print(f"通知を {self.author_email} に送信")
# 3. ログ出力
print(f"ログ: {post['title']} を公開")
設問 1:このコードが抱えている設計上の問題点を挙げよ
次の観点を参考に、具体的に列挙すること:
- 責務分離の欠如(単一クラスに複数の関心事が混在していないか)
- 拡張性・保守性の低さ(変更時に波及が生じやすくないか)
- 再利用性の欠如(同様の処理を他で再利用できるか)
- テスト容易性の低さ(各処理を単体で検証可能か)
設問 2:本クラスをリファクタリングするにあたって、どのような設計改善が有効か
以下の要素を含めて論じること:
- 分離すべき関心事(例:投稿処理、通知処理、ログ処理)
- 各処理を別クラスまたはサービスに分けた場合の利点
- 適用が考えられるデザインパターンと、それぞれの意図・効果
例:適用候補となるパターン
パターン名 | 主な目的と効果 |
---|---|
Facade | 投稿確定処理を 1 つのインターフェースに集約し、呼び出し側を簡潔にする |
Strategy | 通知手段(Email / Slack など)を切り替え可能な構造に分離する |
State | 投稿の状態(下書き / 公開済み など)に応じた振る舞いを柔軟に切り替える |
Composite | 複数の投稿をひとまとまりで扱えるように構造化する(例:一括投稿処理など) |
Iterator | 投稿一覧の処理を外部に公開せず、安全に繰り返し処理できるように設計する |
発展課題(任意)
以下の仕様追加に対して、どのような設計方針で対応するかを検討せよ:
- 投稿に「予約投稿」「公開済み」などの状態管理を導入する
- 通知手段として Slack / LINE / メールなどを外部設定で切り替え可能にする
- 投稿ごとにカスタムテンプレートを適用する機能を追加する
提出フォーマット(チームレビュー・勉強会用)
- 構造上の問題点(最低 3 点)
- リファクタリング方針と理由
- 提案するデザインパターンとその選定理由
- 必要に応じた改善後クラス構造の図解(任意)