Skip to content

MVVMパターン

公開日:November 17, 2024更新日:November 28, 2024
TypeScriptDesign pattern📄

MVVMパターン

MVVMパターン(Model-View-ViewModel Pattern) は、Model、View、ViewModelの3つの部分に分割してアプリケーションを構築するデザインパターンです。このパターンは、特にユーザーインターフェースが重要なアプリケーションで役立ち、ユーザーインターフェース(UI)とビジネスロジックの結合度を減らし、保守性とテスト性を向上させます。

  • Model(モデル): データとビジネスロジックを扱う部分です。データの取得、保存、処理など、アプリケーションのコア機能を提供します。
  • View(ビュー): ユーザーに表示される部分です。画面上にUIを描画し、ユーザーとのインタラクションを担当します。
  • ViewModel(ビューモデル): ViewとModelの間に立ち、Viewの状態を管理し、Modelとのデータバインディングを行います。ViewModelはユーザーの入力を処理し、適切なデータをViewに提供します。

このパターンにより、ViewはViewModelに依存し、ViewModelはModelに依存することで、UIとビジネスロジックを分離し、疎結合な設計を実現します。

TypeScriptでのMVVMパターンの実装

以下に、TypeScriptでMVVMパターンを使用してカウンターアプリケーションを実装する例を紹介します。この例では、ユーザーがボタンをクリックしてカウントを増減させるシンプルなアプリケーションを作成します。

カウンターの例

typescript
// Modelクラス(データとロジックを保持)
class CounterModel {
  private count: number = 0;

  getCount(): number {
    return this.count;
  }

  increment(): void {
    this.count++;
  }

  decrement(): void {
    if (this.count > 0) {
      this.count--;
    }
  }
}

// ViewModelクラス(モデルとビューの仲介をする)
class CounterViewModel {
  private model: CounterModel;
  public count: number = 0;

  constructor(model: CounterModel) {
    this.model = model;
    this.updateCount();
  }

  increment(): void {
    this.model.increment();
    this.updateCount();
  }

  decrement(): void {
    this.model.decrement();
    this.updateCount();
  }

  private updateCount(): void {
    this.count = this.model.getCount();
  }
}

// Viewクラス(ユーザーへの表示)
class CounterView {
  private viewModel: CounterViewModel;

  constructor(viewModel: CounterViewModel) {
    this.viewModel = viewModel;
  }

  render(): void {
    console.log(`Current Count: ${this.viewModel.count}`);
  }

  bindEvents(): void {
    // イベントシミュレーション
    this.viewModel.increment();
    this.render();

    this.viewModel.increment();
    this.render();

    this.viewModel.decrement();
    this.render();
  }
}

// 実際の使用例
const model = new CounterModel();
const viewModel = new CounterViewModel(model);
const view = new CounterView(viewModel);

view.render(); // 初期の表示
view.bindEvents(); // イベントのシミュレーションでカウントの増減

解説

  1. CounterModelクラス(モデル)

    • CounterModelは、カウンターのデータとロジックを保持します。ビジネスロジック(インクリメントやデクリメント)を実装し、アプリケーションのコア機能を担当します。
  2. CounterViewModelクラス(ビューモデル)

    • CounterViewModelは、モデルとビューの仲介役を務めます。モデルからデータを取得し、ビューが使用できる形式で提供します。また、モデルに対して操作を行うメソッド(incrementdecrement)を持っています。
  3. CounterViewクラス(ビュー)

    • CounterViewは、ユーザーに表示する役割を持ちます。ビューはrenderメソッドで現在のカウントを表示し、bindEventsメソッドでユーザーからのアクション(この例ではシミュレーションしたボタンのクリック)をビューモデルに伝えます。
  4. 実際の使用例

    • モデル、ビューモデル、ビューのインスタンスを作成し、ビューがユーザーからの入力を処理してビューモデルを通じてモデルを更新します。そして、更新されたモデルの状態に応じてビューが再描画されます。

利点

  • 双方向データバインディング: ViewとViewModelの間でデータが同期されることで、UIの更新を簡単に行うことができます。
  • 疎結合の実現: Model、View、ViewModelがそれぞれ独立しているため、各部分を変更しても他の部分への影響が最小限に抑えられます。
  • テストのしやすさ: ビューモデルはUIに依存しないため、ビジネスロジックのテストが容易です。

使用例

  • SPA(シングルページアプリケーション): AngularやVue.jsなどのフロントエンドフレームワークでは、MVVMの考え方を使ってUIとビジネスロジックを分離しています。
  • デスクトップアプリケーション: デスクトップアプリケーションでも、UIとロジックを分離するためにMVVMが使われることがあります(例:WPFアプリケーション)。
  • フォーム入力と検証: フォームの入力内容をリアルタイムで検証し、その結果をビューに表示する際にMVVMパターンが役立ちます。

まとめ

MVVMパターンは、Model、View、ViewModelの3つに分割することで、UIとビジネスロジックを分離し、保守性と再利用性を向上させるデザインパターンです。TypeScriptでの実装を通じて、ViewとModelの仲介役を担うViewModelの役割を理解し、UIとロジックの結合を減らす方法を学びました。

このパターンを利用することで、UIとビジネスロジックを独立して開発しやすくなり、拡張性が高く、保守性に優れたアプリケーションを構築することが可能になります。