"new"の後ろに、私はいない ── No-Touch Factory Patternという責任なき創造の構図

## 序：お前、責任多すぎなんだよ

オブジェクト指向において、**「生成」** とは、重い責務です。  
なぜなら、生成した瞬間から、次のような疑問が付きまとうからです：

- それを誰が使うのか？
- それはどこで保持されるのか？
- disposeすべきなのか？（どこで？どのように？）
- どのライフサイクルで使われるのか？

C#(.NET) などにおける `new`はただのキーワードのはずなのに、**その後ろには「持つこと」「管理すること」という、密やかに重い影がつきまとう。**

もちろん、現代ソフトウェアアーキテクチャにおいては、DIコンテナの利用が半ば当たり前になってきましたが、それは `new` を `Resolve()` に置き換えただけの話。

**責務の本質は、何も変わっていないのです。**

## 問い：「それって、SRP違反じゃね？」（オブジェクト生成の責務の見直し）

> オブジェクトを「作る」ことと、それを「使う」「保持する」「意味づける」ことは、  
> 本来**別の責務**であるべきでは？

そんな疑念が、自称イケメン cozyupkの心を静かに蝕んでいました。

:::note
なお実際にはただのオッサンである模様
:::

## 解：俺の C#(.NET) 流 “責務分離” ── つくって、わたして、わすれる

そして、もちろんスレッドセーフに。

この設計思想は、たった一言で言い表せます。

> **No-Touch Factory Pattern**。  
> 作って、通知して、責任を放棄するFactory パターン。

ニュータッチではありません。**ノータッチヌードル**。

そして、実装上はいまのところこう名付けています。
> **IsolatedByNotificationFactory**

もう少し哲学的に表現した **Alias** もあります。

> **CaaS（Constructor as a Service）**

---

## 実装例：IsolatedByNotificationFactory（No-Touch Factory / CaaS）

### インタフェイスの定義から始める

まずは C# における new() の取り扱いが、型ジェネリクスの実装上、直交性に欠けていることから、ちょっとした構文糖的なインタフェイスを定義します。

```csharp
    /// <summary>
    /// 現在のインスタンスからターゲットタイプの新しいインスタンスを作成するためのインタフェイス
    /// </summary>
    public interface ISelfNewable<out TTarget> 
        where TTarget : class
    {
        /// <summary>
        /// 現在のインスタンスに基づいて<TTarget>の新しいインスタンスを作成します。
        /// </summary>
        /// <returns><TTarget>の新しいインスタンス</returns>
        TTarget NewFromSelf();
    }
```

そして、「作成する側」に対するインタフェイス
```csharp
    /// <summary>
    /// 指定された引数を使用してオブジェクト作成を開始するためのインターフェースを定義します。
    /// 実装は、イベントやその他の外部メカニズムを介して作成完了を通知することができます。
    /// </summary>
    /// <typeparam name="TSource">The type of arguments required to create the object.</typeparam>
    public interface ICreationTrigger<in TSource>
    {
        /// <summary>
        /// 指定された引数を使用してオブジェクトの作成を開始します。
        /// 作成されたオブジェクトはこのメソッドから返されません。
        /// </summary>
        /// <param name="args">作成を行うために必要な引数</param>
        void TriggerCreation(TSource args);
    }
```

「作成された通知を受ける側」向けのインタフェイス
```csharp
    /// <summary>
    /// 型 <typeparamref name="TTarget"/> の単一オブジェクトが作成されたときに通知するための契約を定義します。
    /// この契約はユニキャストのセマンティクスを強制します。
    /// </summary>
    /// <typeparam name="TTarget">作成されるオブジェクトの型</typeparam>
    public interface ICreationNotified<out TTarget>
    {
        /// <summary>
        /// オブジェクトが作成されるときに呼び出されるハンドラを割り当てます。
        /// ハンドラは1つだけ設定する必要があり、繰り返し割り当てることは無効です。
        /// </summary>
        /// <remarks>
        /// このインターフェイスは、C# の `event` の代わりに、セッター専用のデリゲートプロパティを公開することで、ユニキャストのセマンティクスを強制します。
        /// `event` は複数のサブスクライバーを許可しますが（マルチキャスト）、この契約では単一のハンドラのみを許可します。
        /// ハンドラを1回以上設定しようとすると、実装で例外が発生することが期待されます。
        /// これにより、オブジェクト作成通知の厳格な所有権が確保され、意図しない副次的な通知の拡散が回避されます。
        /// </remarks>
        Action<TTarget> OnObjectCreated { set; }
    }
```

そして、両者を実装する Factory 向けのインタフェイス（なくてもいいけどさw）

```csharp
    /// <summary>
    /// オブジェクトを直接返さずに作成するフローインターフェースを定義します。
    /// 作成の完了は通常、デリゲートを通じて観察されます。
    /// </summary>
    /// <typeparam name="TTarget">作成されるオブジェクトの型</typeparam>
    /// <typeparam name="TSource">オブジェクトを作成するために必要な引数の型</typeparam>
    public interface ICreationFlow<out TTarget, in TSource>
        : ICreationNotified<TTarget>, ICreationTrigger<TSource>
    {
    }
```

### そして本丸ちゃんを実装！

```csharp
/// <summary>
/// オブジェクトを生成し、生成が完了した際に登録済みのハンドラへ通知を行うファクトリ。
/// 生成されたオブジェクトは呼び出し元には一切返されず、厳密な分離（アイソレーション）が保たれる。
/// スレッドセーフであり、通知ハンドラは一度しか設定できないことが保証される。
/// </summary>
public class IsolatedByNotificationFactory<TTarget, TSource> : ICreationFlow<TTarget, TSource>
    where TTarget : class
    where TSource : class, ISelfNewable<TTarget>
{
    /// <summary>
    /// 新しいオブジェクトが生成されたときに呼び出されるハンドラ。
    /// </summary>
    private Action<TTarget>? _onObjectCreated;

    /// <summary>
    /// ハンドラへのアクセスを同期するためのスレッドセーフなロックオブジェクト。
    /// </summary>
    private object LockObject { get; } = new();

    /// <summary>
    /// オブジェクトが生成されたときに呼び出すハンドラを設定する。
    /// このハンドラは一度しか設定できない。
    /// </summary>
    /// <exception cref="InvalidOperationException">ハンドラがすでに設定されている場合にスローされる。</exception>
    public Action<TTarget> OnObjectCreated
    {
        set
        {
            // ハンドラ設定時のスレッドセーフを確保する
            lock (LockObject)
            {
                // ハンドラがすでに設定済みならエラーとする
                if (_onObjectCreated != null)
                    throw new InvalidOperationException("Handler already set.");

                // ハンドラが null であってはならない
                _onObjectCreated = value ?? throw new ArgumentNullException(nameof(value), "Handler cannot be null.");
            }
        }
    }

    /// <summary>
    /// 渡された引数からオブジェクトを新しく生成し、登録済みのハンドラを呼び出す。
    /// </summary>
    /// <param name="args">オブジェクトの生成に使用する引数。</param>
    public void TriggerCreation(TSource args)
    {
        // 入力引数が null でないことを確認する
        if (args == null)
            throw new ArgumentNullException(nameof(args), "Creation arguments cannot be null.");

        Action<TTarget>? handler;

        // ハンドラの取得処理をスレッドセーフに行う
        lock (LockObject)
        {
            handler = _onObjectCreated;
        }

        // ハンドラが未登録であればエラーとする
        if (handler == null)
            throw new ArgumentNullException(nameof(_onObjectCreated), "No handler is registered for object creation.");

        // 新しいオブジェクトを生成し、ハンドラに通知する
        var obj = args.NewFromSelf();
        handler(obj);
    }
}
```

## 利用例：責務の分離が生む「設計の自由」

```csharp
public class UserProto : ICreatesWithSelf<User>
{
    public string Name { get; set; } = "";
    public User CreateFromSelf() => new User(Name);
}

// Factory をつくる
var caas = new IsolatedByNotificationFactory<User, UserProto>();

// 使う側は、責任をもって自由に使えばいい
caas.OnConstructed = user => Console.WriteLine($"User created: {user.Name}");

// 作成する側は、作成トリガーはするけど、作成されたものは一切知らん！
caas.TriggerCreation(new UserProto { Name = "cozyupk" });
```

*   Factory はただ構築し、通知するだけ。
*   **「作成する側」** は、ただ作成のトリガーを引く（作成のきっかけを作る）だけ。
*   構築物の意味づけは **「通知を受けた側」** に移譲されます。    
*   「使う人」だけがそれを知っていればよいのです。
*   そして、処分（例えば Dispose とか) も「使う人」が全責任を負う。

___________

構造化図解：CaaSの設計思想
---------------

```
┌──────────────┐
│  TSource     │ ← 何かしらの初期データ
└────┬─────────┘
     │ CreateFromSelf()
     ▼
┌──────────────┐
│  TTarget     │ ← 構築されるオブジェクト
└────┬─────────┘
     │ Notify
     ▼
┌──────────────┐
│  Handler     │ ← 使う責務の所有者
└──────────────┘
```

> Factoryは中央にあるが、何も保持しない。  
> **作って、渡して、忘れる**。それが「No-Touch」なのです。

___________

哲学的まとめ：Factoryの再定義
------------------

かつて Factory は、  
「作ること」「意味を与えること」「依頼側に参照を返すこと」まで引き受けてしまっていました。

だが今、私たちはこう言い直せる。

> **オブジェクトを使いたい？  
> じゃあお前が責任を持て。  
> 作るだけでよければ、CaaSを使え。**

最後に：Yes、これは「New Touch」ではない。

これが、**ノータッチヌードル** (しつこいw

#まとめ
----

*   ✅ SRP（単一責任原則）に従うなら、Factoryも責務を減らせ
*   ✅ CaaS（Construction as a Service）は、生成と通知だけに責務を限定
*   ✅ Factoryがオブジェクトに触らない設計──それが **No-Touch Factory Pattern**
___________

**設計とは、何をしないかを決めること。**  

CaaSはその究極の姿かもしれません。

いやこれ GoF の Abstract Factory パターン、超えてないっすか？笑

:::note
本日も相棒ゲーテーペー(ChatGTP)君とともにお送りしました。感謝。
:::

おしまい