Angularのアプリケーションを設計していると、「処理を切り替えたい」「サービスを共通化したい」「RxJSをもっと上手く使いたい」といった悩みが出てきませんか?
そういったときに役立つのが「デザインパターン(設計パターン)」です。
この記事では、Angularでよく使われる7つのデザインパターンを紹介します。現場でもよく使われるパターンばかりなので、実装の引き出しを増やしたい方はぜひ参考にしてください。
Strategy Pattern(ストラテジーパターン)
- 目的:処理(戦略)を動的に切り替える
- 使いどころ:フォームのプレースホルダーやバリデーションを条件ごとに切り替える
export interface PlaceholderStrategy { getPlaceholder(): string; } @Injectable() export class AdminPlaceholderStrategy implements PlaceholderStrategy { getPlaceholder() { return '管理者用プレースホルダー'; } }
コンポーネント側では PlaceholderStrategy をDIで受け取り、戦略の中身を差し替えることで処理を切り替えます。
✅ なぜこれが「デザインパターン」なのか?
デザインパターンとは「再利用可能な設計上の知恵(設計指針)」であり、特定の実装言語や技術に依存しません。 Angularであっても、意図的に戦略(アルゴリズムや処理)を切り替える設計をしている時点で、それは「ストラテジーパターン」と呼ぶことができます。
そのため、「AngularでDIを活用して戦略を差し替えている構成」はまさにこのパターンの応用例です。
Singleton Pattern(シングルトンパターン)
- 目的:インスタンスを1つに固定してアプリ全体で共有
- 使いどころ:認証状態や共通の設定情報など
@Injectable({ providedIn: 'root' }) export class AuthService { private token = ''; }
Angularのサービスは providedIn: 'root' によって自動的にシングルトンになります。
Factory Pattern(ファクトリーパターン)
export function configFactory(): ConfigService { return new ConfigService(environment.production); } providers: [ { provide: ConfigService, useFactory: configFactory } ]
状況に応じて返すサービスを変えられるので、テストや環境ごとの切り替えに便利です。
Observer Pattern(オブザーバーパターン)
- 目的:状態の変化を監視・通知する
- 使いどころ:状態管理、非同期イベント、フォームの変化監視など
private subject = new Subject<string>(); notify(message: string) { this.subject.next(message); } get messages$(): Observable<string> { return this.subject.asObservable(); }
RxJSを使うことでオブザーバーパターンを自然に導入できます。
Facade Pattern(ファサードパターン)
@Injectable() export class UserFacade { constructor( private authService: AuthService, private userService: UserService ) {} loadUser() { if (this.authService.isAuthenticated()) { return this.userService.getUser(); } return of(null); } }
コンポーネント側の依存が減ることで、テストや保守がしやすくなります。
Dependency Injection(依存性注入パターン)
- 目的:依存オブジェクトを外部から注入して柔軟性を高める
- 使いどころ:Angularの全てのサービス設計
constructor(private userService: UserService) {}
Angular自体がこのパターンをベースに成り立っています。DIを正しく理解すると、モジュール設計が楽になります。
Command Pattern(コマンドパターン)
- 目的:処理をオブジェクトとして抽象化し、実行履歴や取り消しを管理
- 使いどころ:複雑なアクション処理、履歴管理、Undo処理など
interface Command { execute(): void; } class SaveCommand implements Command { constructor(private service: DataService) {} execute() { this.service.save(); } }
Angularでコマンドパターンを使う場面は限られますが、処理を疎結合に保ちたいときには有効です。
まとめ:パターン一覧
| パターン名 | 主な用途 | 使いどころ例 |
|---|---|---|
| Strategy Pattern | 処理の切替を柔軟に | フォームの入力や表示ロジックなど |
| Singleton Pattern | インスタンスを1つに固定 | サービス、設定、状態管理 |
| Factory Pattern | インスタンスの生成を外部に任せる | 環境ごとのサービス切り替え |
| Observer Pattern | 状態変化の購読と通知 | RxJSによる状態管理 |
| Facade Pattern | 複雑な処理を簡単な窓口にまとめる | コンポーネントとサービスの橋渡し |
| Dependency Injection | 柔軟でテストしやすい設計を実現 | 全サービス、コンポーネント設計 |
| Command Pattern | 処理をオブジェクト化して履歴や再実行可能に | 複雑なビジネスロジックや履歴処理 |
おわりに
Angularのような大規模フレームワークでは、デザインパターンを理解しておくことで設計の引き出しが格段に広がります。
パターンを知っていると「なぜこの構造なのか」「この処理はどこに分離すべきか」といった判断も速くなり、保守性・テスト性の高いコードが書けるようになります。
現場での実践にもぜひ活かしてみてください!