Skip to content

MS_DesignPatterns

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

デザイン・パターン

概要

  • 過去のソフトウェア設計者が発見し編み出した設計ノウハウを蓄積し、
    名前をつけ、再利用しやすいように特定の規約に従ってカタログ化したもの。

  • 後述の GoF や Code Complete などの書籍が有名。

  • .NET のクラスライブラリの中でどのように使用されているか?
    などの例を挙げながら、ぼちぼち書き足していく。

移行メモ(誤字): 移行元の「例を上げらながら」を
「例を挙げながら」に修正した。

GoFパターン

  • 多数のソフトウェアパターンの中で最も広く知られている。

  • GoF とは、書籍『オブジェクト指向における再利用のためのデザインパターン』の著者である、
    エーリヒ・ガンマ、リチャード・ヘルム、ラルフ・ジョンソン、ジョン・ブリシディースの
    4 人を指す。

  • 特定の規約に従ってカタログ化。

    • 生成に関するパターン
    • 構造に関するパターン
    • 振る舞いに関するパターン
    • マルチスレッドプログラミングに関するパターン

補足(GoF は 3 分類である): 上記の 4 分類のうち、
「マルチスレッドプログラミングに関するパターン」は GoF には含まれない

【GoF の 23 パターンの分類】★
   ・生成(Creational)  5 個
   ・構造(Structural)  7 個
   ・振る舞い(Behavioral)11 個
   → 【合計 23 個。これで全部】

【マルチスレッド系のパターンの出典】
   ・GoF ではなく、
     - 『Pattern-Oriented Software Architecture』(POSA)
     - Doug Lea『Concurrent Programming in Java』
     - 結城浩『Java言語で学ぶデザインパターン入門
       マルチスレッド編』★
     などに由来する
   → 本ページの後半で挙げられている
     Producer-consumer / Thread pool /
     Readers-writer lock 等はこの系統

   → 【並列に扱われていること自体は有用】だが、
     出典が異なる点は押さえておくとよい

注意および批判

  • よく使われる設計を一般化された形で(コンセプトとして)まとめたもの。
  • サンプルコードは、実装例に過ぎない。
  • デザインパターンは、すべての状況における最善の設計ではない。
  • デザインパターンをむやみに適用するのは不適切で、コードの複雑さを無意味に高める。
  • 一部のデザインパターンは、プログラミング言語の機能の欠損の印と主張されることがある。

補足(最後の批判は .NET で実証されている): 「言語機能の欠損の印」という
主張は、C# の進化がそのまま裏付けになっている

【言語機能に吸収されたパターン】★
   Iterator      → 【yield return / foreach】★
                   IEnumerator を手で書く必要がなくなった
   Observer      → 【event / IObservable<T>】★
   Command       → 【デリゲート / Action / Func】
                   「操作をオブジェクトにする」ために
                   クラスを作る必要がない
   Strategy      → 【デリゲート / ラムダ式】
                   小さな戦略なら 1 行で渡せる
   Singleton     → 【static / Lazy<T> / DI コンテナ】★
                   自前実装は不要
   Null Object   → 【Nullable 参照型 / null 合体演算子】
   Decorator     → 【拡張メソッド】(一部の用途)
   Template Method → 【デリゲートの注入】
   Visitor       → 【パターン マッチング(switch 式)】★
                   C# 8/9 以降、型による分岐が簡潔に書ける
   Prototype     → 【record の with 式】★

【残っているもの】
   ・Factory / Abstract Factory
     → DI コンテナが実質的に担う
   ・Facade / Adapter / Proxy
     → 【設計上の意図】であり、言語機能では消えない ★
   ・Composite / Mediator / State
     → 構造そのものが必要な場合は今も有効

→ 「パターンを知る意味」は
  【実装手順】ではなく【設計の語彙】にある ★
  (「ここは Adapter」と言えば意図が通じる)

GoFパターン

生成に関するパターン

Abstract Factory

  • 関連する一連のインスタンスを状況に応じて、適切に生成する方法を提供する。

Builder

  • 接続文字列を生成する SqlConnectionStringBuilder など。
  • 複合化されたインスタンスの生成過程を隠蔽する。

Factory Method

  • データ プロバイダのインスタンスを生成する DbProviderFactory など。
  • 実際に生成されるインスタンスに依存しない、インスタンスの生成方法を提供する。

Prototype

  • ICloneable.Clone(), Object.MemberwiseClone() などがある。
  • 同様のインスタンスを生成するために、原型のインスタンスを複製する。

Singleton

  • GetInstance メソッドを持つクラス、WCF の IInstanceProvider インターフェイスなどが該当。
  • あるクラスについて、インスタンスが単一であることを保証する。

補足(.NET の実例に対する注記): 挙げられている実例は的確だが、
現在の推奨と食い違うものがある。

【ICloneable は使ってはいけない】★
   ・Microsoft 自身が【使用を推奨していない】
   ・理由:Clone() が
     【浅いコピーか深いコピーか規定されていない】
     → 呼ぶ側が判断できない
   → 自前の Clone メソッドか、
     【record の with 式】を使う ★
       var b = a with { Name = "x" };

【Singleton は自前実装しない】★
   ・スレッド セーフな実装は意外に難しい
     (二重チェック ロック、メモリ バリア)
   ・現在は
       - 【DI コンテナのシングルトン登録】★
         services.AddSingleton<IFoo, Foo>()
       - 【Lazy<T>】
       - static readonly フィールド(型初期化子)
     で足りる
   ・そもそも
     【グローバル状態はテストを難しくする】
     → DI で注入する形にすれば
       テスト時に差し替えられる ★

【DbProviderFactory は現在も現役】
   → [ADO.NETデータプロバイダ](MS_ADONETDataProvider) 参照
   → 「DB の種類を設定で切り替える」ための仕組み

構造に関するパターン

Adapter

  • TableAdapter、DataAdapter などがある。
  • 元々関連性のない 2 つのクラスを接続するクラスを作る。

Bridge

  • クラスなどの実装と、呼出し側の間の橋渡しをするクラスを用意し、実装を隠蔽する。

Composite

  • 例えば、DataTable は DataColumn や DataRow などから構成される。
    多数の UI Control をホストする、Form(Windows Forms や Web Forms)なども。
  • 再帰的な構造を表現する。複雑なオブジェクトモデルを持つオブジェクト。

Decorator

  • System.IO.Stream クラス系のデコレート・パターンが有名(ファイル IO +暗号化など)。
  • あるインスタンスに対し、動的に付加機能を追加する。Filter とも呼ばれる。

Facade

  • 業務系では、Transaction ルートを定義する際に使用される。
  • 複数のサブシステムの窓口となる共通のインタフェースを提供する。

移行メモ(誤字): 移行元の「Transaction ルートを定義する際にしようされる」を
使用される」に修正した。

Flyweight

  • 多数のインスタンスを共有し、インスタンスの構築のための負荷を減らす。

Proxy

  • 透過プロキシ
    (System.Runtime.Remoting.Proxies.RealProxy)などで利用されている。
  • 共通のインタフェースを持つインスタンスを内包し、利用者からのアクセスを代理する。
    Wrapper とも呼ばれる。

補足(System.IO.Stream は Decorator の教科書的な実例): 本ページで
「有名」とされているこの例は、実際に .NET を理解する近道である。

【Stream の合成】★
   FileStream                      … 実体(ファイル)
     └ CryptoStream                … 暗号化を足す
         └ GZipStream              … 圧縮を足す
             └ StreamWriter        … 文字列で書けるようにする

   using var fs  = File.Create("a.dat");
   using var enc = new CryptoStream(fs, transform, Write);
   using var gz  = new GZipStream(enc, CompressionMode.Compress);
   using var sw  = new StreamWriter(gz);
   sw.Write("hello");

   → 【どれも Stream 型】なので
     好きな順に積み重ねられる ★
   → 継承ではなく【合成】で機能を足す
     = Decorator の本質

【同じ発想の現代的な例】
   ・ASP.NET Core の【ミドルウェア パイプライン】★
     app.UseHttpsRedirection()
        .UseAuthentication()
        .UseAuthorization()
     → 各段が次を包む=Decorator の連鎖
   ・【DelegatingHandler】(HttpClient)
     → リトライ・ログ・認証を層として足す
   → [AOP](MS_AOP) の発想とも通じる
【Proxy と RealProxy の現況】★
   ・RealProxy は【.NET Remoting の一部】であり、
     【.NET Core 以降には存在しない】★
   ・現在 AOP 的な差し込みを行うなら
       - 【DispatchProxy】(.NET Standard 2.0〜)★
         → RealProxy の後継。動的プロキシを作れる
       - Castle DynamicProxy(OSS)
       - 【ソース ジェネレータ】(コンパイル時に織り込む)
       - DI コンテナのインターセプタ機能
   → 詳細は
     [.NETにおいてAOPを実現する透過プロキシ](MS_TransparentProxyForAOP)

振る舞いに関するパターン

Chain of Responsibility

  • イベントの送受信を行う複数のオブジェクトを鎖状につなぎ、
    それらの間をイベントが渡されてゆくようにする。

Command

  • 複数の異なる操作について、それぞれに対応するオブジェクトを用意し、
    オブジェクトを切り替えることで、操作の切替えを実現する。

Interpreter

  • 構文解析のために、文法規則を反映するクラス構造を作る。

Iterator

  • 配列、Collection、Generic など、沢山のものがある。

    • System.Collections.IList、System.Collections.Generic.IList(T) インターフェイス
    • System.Collections.IEnumerator、
      System.Collections.Generic.IEnumerator(T) インターフェイス
    • System.Collections.IEnumerable、
      System.Collections.Generic.IEnumerable(T) インターフェイス
    • System.Collections.ICollection、
      System.Collections.Generic.ICollection(T) インターフェイス
  • 複数の要素を内包するオブジェクトのすべての要素に対して、
    順番にアクセスする方法を提供する。反復子。

Mediator

  • オブジェクト間の相互作用を仲介するオブジェクトを定義し、
    オブジェクト間の結合度を低くする。

Memento

  • データ構造に対する一連の操作のそれぞれを記録しておき、
    以前の状態の復帰または操作の再現が行えるようにする。

Observer (出版-購読型モデル)

  • Reactive Extensions(Rx) などが有名。
  • インスタンスの変化を他のインスタンスから監視できるようにする。
    Listener とも呼ばれる。

State

  • オブジェクトの状態を変化させることで、処理内容を変えられるようにする。

Strategy

Template Method

  • 後述の IoC、AOP → DI → 依存性反転原則
  • あるアルゴリズムの途中経過で必要な処理を抽象メソッドに委ね、
    その実装を変えることで処理が変えられるようにする。

Visitor

  • データ構造を保持するクラスと、それに対して処理を行うクラスを分離する。

補足(Iterator は C# の中核機能になった): 本節で最も.NET と
深く結び付いているパターンなので補っておく。

【yield return が生成するもの】★
   IEnumerable<int> Take3() {
       yield return 1;
       yield return 2;
       yield return 3;
   }
   → コンパイラが
     【IEnumerator<T> を実装したステートマシン】を
     自動生成する ★
   → 手で Iterator を書く必要がなくなった

【遅延評価という副産物】★★
   ・yield は【呼ばれるまで実行されない】
   ・LINQ の Where / Select も同じ
     → 巨大なファイルを 1 行ずつ処理できる
     → 【メモリに全部載せなくてよい】
   ・落とし穴
     - 【列挙するたびに再実行される】★
       → 副作用があると 2 回起きる
       → 必要なら .ToList() で確定させる
     - デバッグ時に「なぜここで例外?」となる
       (実際に走るのは foreach の時点)

【非同期版】
   ・【IAsyncEnumerable<T> / await foreach】(C# 8〜)★
     → DB やネットワークからの
       ストリーミング読み取りに使う
【Strategy / Template Method と DI の関係】★
   原文が両者に [IoC、AOP → DI → 依存性反転原則] を
   充てているのは【的確】である。

     Template Method … 継承で差し替える(静的)
     Strategy        … 合成で差し替える(動的)★
     DI              … Strategy を
                       【外部から注入する】仕組み

   → 「継承より合成」(GoF の原則)が
     DI という形で標準化された、と読める

マルチスレッドプログラミングに関するパターン

Active Object (Actor)

Future

Guarded suspension

  • 前提条件が満たされるまで待機するための機構。
  • System.Threading.SpinLock 構造体、逆セマフォなど。

Lock

  • リソースに対して 1 つのスレッドが「ロック」をかけて、
    その間は他のスレッドがそのリソースにアクセスしたり変更を加えたりできないようにする。

  • Windows OS のスレッド同期ツールキットを使う、

    • lock ステートメント
    • System.Threading.Mutex クラス
    • System.Threading.Semaphore クラス

    などがある。

  • 参考

Monitor

  • 排他的に実行しなければならないメソッド群を持つ
    オブジェクトをスレッドセーフに利用できるようにするための機構。
  • 名前の通り、System.Threading.Monitor クラスがある。

Producer-consumer

  • 「生産者」 (producer) スレッド群がデータを生成して「通信路」に追加し、
    「消費者」 (consumer) スレッド群がそのデータを「通信路」から取り出して
    処理するという構造。

  • Producer-consumer を取り入れたクラスに、System.Threading.ThreadPool がある。

Reactor

Readers-writer lock

  • 書き込みは排他アクセスが必要だが、読み込みは並行に行えるようにしたい場合の
    ためのロック機構。
  • 名前の通り、System.Threading.ReaderWriterLock がある。

Scheduler

  • Windows OS にノンプリエンプティブなマルチタスク、協調的マルチタスクを実現するための
    ファイバー(fiber)があるが、.NET にはない(マイクロスレッドで実装することはできる)。

  • シングルスレッドで実行される処理の実行を各スレッドに許可するタイミングを明確に制御する。

  • 参考

Thread pool

  • 多数のスレッドを作成して、それらに多数のタスクを処理させる。
  • 一般に、前述の Producer-consumer パターンを使って実現される。
  • 名前の通り、System.Threading.ThreadPool クラスがある。

Thread-specific storage

Windows の OS 機能に TLS: Thread Local Storage がある。

  • この、TLS には、ThreadStatic 属性や ThreadLocal オブジェクト経由でアクセス可能。
  • 静的変数・グローバル変数のように扱えるが
    スレッドごとに異なる内容を格納できるメモリ領域を提供する。

Two-phase termination

補足(.NET の並行処理は「パターンを書かない」方向へ進んだ): 本節の
一覧は概念の整理として有用だが、実装手段は大きく変わった。

【現在の .NET での対応物】★
   Future            → 【Task / Task<T>】★
                       (原文が空欄なのは執筆時期による)
   Active Object     → Actor モデル(Akka.NET / Orleans)
                       または Channel + 単一コンシューマ
   Producer-consumer → 【System.Threading.Channels】★★
                       または BlockingCollection<T>
   Guarded suspension→ SemaphoreSlim.WaitAsync /
                       TaskCompletionSource
   Readers-writer lock → 【ReaderWriterLockSlim】★
                       (ReaderWriterLock は非推奨。遅い)
   Thread pool       → Task.Run(内部でプール利用)
   Scheduler         → TaskScheduler /
                       SynchronizationContext
   Two-phase termination
                     → 【CancellationToken】★★
                       (協調的キャンセルの標準形)

【いちばん重要な変化】★
   「スレッドを直接扱う」から
   【「Task と async/await で書く」】へ移った
     → ロックを書く機会そのものが減った
     → 待つ間スレッドを占有しない
【Channels(現在の Producer-consumer)】★
   var ch = Channel.CreateBounded<Item>(100);
   // producer
   await ch.Writer.WriteAsync(item);
   ch.Writer.Complete();
   // consumer
   await foreach (var i in ch.Reader.ReadAllAsync(token))
       Process(i);

   → 【バックプレッシャ】(容量上限)を持てる
   → 非同期で待てる(スレッドを消費しない)★
   → BlockingCollection は同期ブロックするため
     現在は Channels が推奨
【ロックに関する現代的な注意】★
 ・【async メソッド内で lock してはいけない】
     → await を挟めない(コンパイル エラー)
     → 【SemaphoreSlim.WaitAsync】を使う ★
 ・lock の対象は private readonly object にする
     → this や typeof(X) をロックしない
 ・.NET 9 では【System.Threading.Lock】型が追加され、
   lock ステートメントが最適化された
 ・そもそも【共有状態を作らない】のが最良
     → イミュータブル、Channel での受け渡し

アーキテクチャに関するパターン

データ・アクセスのアーキテクチャに関するパターン

Active Record

  • Ruby on Rails では、

    • データベース定義からほぼ自動で CRUD 操作を備えたクラスを生成する。
    • 一方でその性質上、複雑な設計のデータベースとは相性が悪い。
  • Active Record - Wikipedia
    https://ja.wikipedia.org/wiki/Active_Record

Data Access Object

  • 後述の多層アーキテクチャのデータ・アクセスに合致。

  • Data Access Object - Wikipedia
    https://ja.wikipedia.org/wiki/Data_Access_Object

    Java では、Data Access Object は数々の複雑で多様な 永続性技術
    (JDBC、JDO、EJB CMP、TopLink、Hibernate、iBATIS など)
    からアプリケーション本体を隔離するのに利用される。

Data Transfer Object

  • DTO(POXO : Plain Ordinary XXXX Object とも)

    • .NET:POCO
    • Ruby:PORO
    • Swift:POSO
    • PHP、Python:POPO
    • Java、JavaScript:POJO
  • アプリケーションソフトウェアのサブシステム間でデータを転送するのに使う。

  • もともと、EJB における後述のモックオブジェクト文化から広まったらしい。

  • また、JavaScript では、Ajax の分野で利用された JSON 文化から広まった。

  • Data Transfer Object - Wikipedia
    https://ja.wikipedia.org/wiki/Data_Transfer_Object

    自身のデータの格納と取り出し機能
    (アクセサメソッドとミューテータメソッド)しか持たない。

補足(Active Record と DAO の対立軸): この 2 つは
データ アクセス設計における根本的な選択である。

【Active Record】★
   ・【データとその永続化ロジックを同じクラスに置く】
       user.Save();  user.Delete();
   ・利点:書く量が少ない。学習が容易
   ・欠点
       - ドメイン モデルが【DB のテーブル構造に縛られる】
       - 単体テストで DB が必要になりやすい ★
       - 「複雑な DB と相性が悪い」(原文の指摘どおり)

【DAO / Repository】
   ・【データと永続化を分離する】
       repository.Save(user);
   ・利点:ドメイン モデルが DB から独立する
   ・欠点:クラスが増える

【.NET での現在地】★
   ・【Entity Framework Core】は
     両者の中間(Unit of Work + Repository に近い)
     → DbContext が Unit of Work
     → DbSet<T> が Repository
     → 【EF Core の上にさらに Repository を被せるか】は
       長年の論争がある ★
       - 被せる派:テスト容易性、DB 非依存
       - 被せない派:EF Core 自体が抽象化済み、
         IQueryable の表現力を殺す
   ・【Dapper】は DAO 寄り
     → SQL を書き、結果を POCO に詰める

【DTO について】★
   ・現在の .NET では
     【record】が DTO に最適
       public record UserDto(int Id, string Name);
     → イミュータブル、値等価、簡潔
   ・API の境界では
     【エンティティをそのまま返さない】のが定石 ★
     → 過剰な情報の露出を防ぐ
     → DB スキーマの変更が API 契約に漏れない

UIのアーキテクチャに関するパターン

MVC

ASP.NET MVC などで利用されている。

MVVM

前述の MVC と同様に「プレゼンテーションとドメインを分離」することで、
アプリケーション開発における保守性・開発生産性に寄与する。

補足(MVVM の詳細は別ページにある): 本 Wiki 内では
XAMLの書き方(2) に MVVM の節があり、
ガイドラインと現在の実装手段(CommunityToolkit.Mvvm 等)が整理されている。

その他のアーキテクチャに関するパターン

Front Controller パターン

後述の「プレゼンテーション層のパターン」の Front Controller を参照。

Identity map パターン

Interceptor パターン

Naked objects

Service locator パターン

Specification パターン

出版-購読型モデル

  • 非同期メッセージングパラダイムの一種。

  • メッセージキュー・パラダイムと対比されるため、メッセージ・システムは、
    出版-購読型とメッセージキューの両モデルをサポートしている。

  • 特徴

    • メッセージの送信者(出版側)が特定の受信者(購読側)を想定せずに
      メッセージを送るようプログラムされたもの。
    • 出版側と購読側の結合度が低いため、スケーラビリティがよく、
      動的なネットワーク構成に対応可能。
  • 実装

    • 出版側のメッセージはクラス分けされ、購読者に関する知識を持たない。
    • 購読側は興味のあるクラスを指定しておき、
      そのクラスに属するメッセージだけを受け取り、出版者についての知識を持たない。
  • 出版-購読型モデル - Wikipedia
    https://ja.wikipedia.org/wiki/%E5%87%BA%E7%89%88-%E8%B3%BC%E8%AA%AD%E5%9E%8B%E3%83%A2%E3%83%87%E3%83%AB

多層アーキテクチャ

  • アプリケーションを複数の "層" に分け、それらを独立したモジュールとして開発・保守する。

    • 各層はインタフェースを定義しモジュール化されたソフトウェアであり、
    • テクノロジーの進歩や要求の変化に合わせて各層を個別に置換できる。
    • クライアントサーバモデル

      • ユーザインタフェース
      • ビジネスロジック
      • データアクセス
    • Web 開発

      • プレゼンテーション層 : 変化しないコンテンツを供給する Web サーバ
      • 中間層 : 動的コンテンツを生成するアプリケーションサーバ。
      • データ層 : データベースとその管理システム。
  • 多層アーキテクチャ - Wikipedia
    https://ja.wikipedia.org/wiki/%E5%A4%9A%E5%B1%A4%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3

補足(Service locator は現在アンチパターン扱い): 一覧に名前だけ
挙がっているが、評価が定まっているので補足しておく。

【Service Locator】★
   ・「必要な依存をコンテナから【自分で取りに行く】」
       var svc = ServiceLocator.Get<IFoo>();

【なぜアンチパターンとされるか】★★
 ① 【依存関係が signature に現れない】
     → コンストラクタを見ても何に依存しているか不明
     → 実行して初めて分かる
 ② テストで【何をモックすべきか分からない】
 ③ ロケータ自体がグローバル状態になる

【DI(コンストラクタ注入)との違い】
   ✕ Service Locator
       class Foo { void M() { var b = Locator.Get<IBar>(); } }
   ○ 依存性の注入 ★
       class Foo { Foo(IBar bar) { _bar = bar; } }
       → 【依存が明示される】
       → コンパイラが不足を教えてくれる

【例外的に使われる場面】
   ・DI コンテナを使えない層(静的メソッド、
     レガシー コードとの境界)
   ・フレームワークの内部(コンテナ自身)
   → 【アプリのコードでは避ける】★
   → 詳細は [DI](MS_DI) /
     [IoC、AOP → DI → 依存性反転原則](MS_IoCAOPDI)
【出版-購読型モデルの現在】★
   ・.NET 内 → MediatR、[Reactive Extensions(Rx)](MS_ReactiveExtensions)
   ・プロセス間 → 【Azure Service Bus / RabbitMQ /
                   Kafka / MQTT】★
   ・注意点
     - 【メッセージの順序保証】は自明でない
     - 【at-least-once】が基本
       → 受信側の【冪等性】が必須 ★
     - 疎結合の代償として
       【全体の流れが追いにくくなる】
       → 分散トレーシング(OpenTelemetry)が要る

多層アーキテクチャのパターン

プレゼンテーション層のパターン

Application Controller

Composite View

Context Object

Dispatcher View

Front Controller

MVC 系のフレームワークに実装されているアレ

Intercepting Filter

MVC 系のフレームワークに実装されているアレ

Service To Worker

View Helper

MVC 系のフレームワークに実装されているアレ

補足(この 3 つは ASP.NET Core でも健在): 「MVC 系のフレームワークに
実装されているアレ」という説明のとおり、現在も中核にある

【ASP.NET Core での対応】★
   Front Controller
     → 【ルーティング ミドルウェア】
       すべてのリクエストが 1 つのパイプラインを通る
     → 認証・認可・ローカライズも
       原文の一覧どおりここで処理される ★

   Intercepting Filter
     → 【ミドルウェア】(パイプライン全体)
     → 【フィルター】(MVC の中)★
         - Authorization / Resource / Action /
           Exception / Result フィルター
         - [Authorize]、[ValidateAntiForgeryToken] 等

   View Helper
     → 【タグ ヘルパー】(asp-for 等)★
     → 【ビュー コンポーネント】
     → HTML ヘルパー(@Html.*)は今も使えるが、
       タグ ヘルパーの方が HTML らしく書ける
【ミドルウェアとフィルターの使い分け】★
   ミドルウェア … 【全リクエスト】が対象
                  MVC を知らない(静的ファイルも通る)
                  → 圧縮、CORS、認証、例外の最終防壁
   フィルター   … 【MVC のアクション】が対象
                  モデル バインド結果を見られる ★
                  → 認可、入力検証、キャッシュ

   → 「どちらで書くか」の判断は
     【MVC の文脈が必要かどうか】で決まる

ビジネス層のパターン

Application Service

Business Delegate

Business Object

Composite Entity

Service Locator

Session Facade

Transfer Object Assembler

Transfer Object

Value List Handler

インテグレーション層のパターン

Data Access Object

前述の「データ・アクセスのアーキテクチャに関するパターン」の
Data Access Object を参照。

Domain Store

Service Activator

Web Service Broker

補足(この節の出典): 「多層アーキテクチャのパターン」以下に
列挙されているパターン名は、J2EE パターン カタログに由来する。

【出典】★
   『Core J2EE Patterns』
     (Deepak Alur, John Crupi, Dan Malks / Sun Microsystems)
   ・プレゼンテーション層 / ビジネス層 /
     インテグレーション層 の 3 層に分けて
     パターンをカタログ化したもの
   ・2001年(第 1 版)/ 2003年(第 2 版)

【現在の評価】
   ・【EJB 2.x 時代の制約への対処】が動機のものが多い
     - Business Delegate  … リモート呼び出しの隠蔽
     - Session Facade     … 粒度の細かい呼び出しの削減
     - Transfer Object    … リモート越しのデータ転送
     → EJB 3 以降、これらの制約が緩和され
       【不要になったパターンがある】★

   ・一方、【今も有効なもの】
     - Front Controller / Intercepting Filter /
       View Helper(前述のとおり現役)★
     - Data Access Object
     - Service Activator(≒ メッセージ受信ハンドラ)

【読み方の指針】★
   ・パターン名を「覚える」のではなく、
     【どんな制約への対処だったか】を見る
   ・制約が消えていれば、パターンも不要になる
     → 本ページ冒頭の「注意および批判」の
       「言語機能の欠損の印」という指摘と同じ話 ★

その他のパターン

遅延読み込み

モックオブジェクト

ソフトウェアテスト時、特に

  • テスト駆動開発
  • ビヘイビア駆動開発

における代用の下位モジュールスタブの一種。

Abstract Server パターン

Factory パターン

Monostate パターン

Null object パターン

Object pool パターン

Servant (デザインパターン)

Stairway to Heaven

Type Tunnel パターン

補足(テスト ダブルの用語整理): 「モックオブジェクト」は
総称として使われがちだが、実は下位分類がある

【テスト ダブル(Test Double)の分類】★
   ・【Dummy】  … 引数を埋めるためだけ。使われない
   ・【Stub】   … 決まった値を返す(状態の検証)★
   ・【Spy】    … 呼ばれたことを記録する
   ・【Mock】   … 【呼ばれ方を検証する】(振る舞いの検証)★
   ・【Fake】   … 簡易だが動く実装
                  (インメモリ DB、偽のメール送信)★

   → 原文が「スタブの一種」としているのは
     広義の使い方であり、
     厳密には Stub と Mock は【検証の観点が違う】

【.NET での実装】
   ・【Moq】/ NSubstitute / FakeItEasy
     → 動的プロキシでインターフェースを実装する
   ・【インターフェースを切っていないと使えない】★
     → だから DI と組み合わせる

【モックを使いすぎる弊害】★
   ・実装の詳細に結び付いたテストになり、
     リファクタリングのたびにテストが壊れる
   → 【Fake(動く簡易実装)】や
     【Testcontainers で本物の DB を立てる】方が
     壊れにくいことが多い ★
   → 詳細は [単体・結合テスト方式](MS_UnitAndIntegrationTestMethods)

参考

DI

IoC

AOP

依存性反転原則

(いずれも IoC、AOP → DI → 依存性反転原則 の該当節を参照)

Wikipedia

デザインパターン

IoC

C#とJavaによるデザインパターンへのお誘い

https://www.hyuki.com/pi/

C#で学ぶデザインパターン入門 - Qiita

移行メモ(リンクの重複・欠落): 上記の Qiita 一覧には
Builder と Bridge が同一の URL13e37d54e04b61bc69b5)に
なっている箇所がある(Bridge 側が誤りと思われる)。
また Composite Pattern には URL がない
いずれも移行元のまま残した。

CodeZine(コードジン)

デザインパターンの使い方連載一覧
https://codezine.jp/article/corner/207

移行メモ(リンク切れ): 参考の
www.samuraiz.co.jp/adobeproduct/jrun/...(Adobe JRun は
2011 年頃に提供終了)は到達しない可能性が高い。記録として残す。


Tags: 移行, プログラミング, .NET開発

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally