Windows Formsの呪縛を解く:密結合を排した「画面遷移アーキテクチャ」の極意
多くのVB.NETエンジニアが、`Form1.Show()` と `Me.Hide()` の連鎖という「スパゲッティの迷宮」で立ち往生している。これは単なるコードの汚染ではない。メモリリーク、イベントハンドラの二重登録、そしてDispose漏れという、Windows Formsにおける「死の三重奏」を奏でているに等しい。
長年レガシーシステムの再構築に従事してきた経験から断言する。画面遷移を「画面同士の直接参照」で実装している限り、そのシステムは負債である。
本稿では、DIコンテナを応用した疎結合な画面遷移アーキテクチャを提示する。
—
1. なぜ「直接参照」がシステムを殺すのか
`Form1` が `Form2` を `New` して呼び出す。このとき、`Form1` は `Form2` の存在を物理的に知る必要がある。これではユニットテストは不可能であり、メモリのライフサイクル管理は個々の開発者の「善意」に委ねられることになる。
真のアーキテクトは、「画面は単なる表示器(View)であり、ビジネスロジックや遷移制御とは別個の存在である」と定義する。
2. インターフェイスによる抽象化とDIの導入
まずは、各フォームを制御するための抽象化を行う。ここで重要なのは、フォームの生成を自前で行わず、DIコンテナ(あるいはシンプルなファクトリパターン)に委譲することだ。
‘ 画面遷移を抽象化するインターフェイス
Public Interface IView
Sub ShowView()
Sub CloseView()
End Interface
‘ Form2のインターフェイス定義
Public Interface IForm2
Inherits IView
Property DataContext As String
End Interface
3. 画面遷移制御クラス(Navigator)の構築
フォーム同士を直接会話させず、`Navigator` クラスを介在させる。これにより、メモリ管理を一元化できる。
Public Class ViewNavigator
‘ フォームのインスタンスを保持し、再利用または明示的破棄を管理する
Private _currentForm As Form
Public Sub NavigateTo(Of T As {Form, IView})(factory As Func(Of T))
‘ 現在のフォームを閉じる前にリソースを明示的に解放
If _currentForm IsNot Nothing Then
_currentForm.Close()
_currentForm.Dispose()
End If
‘ コンテナからインスタンスを生成
_currentForm = factory()
_currentForm.Show()
End Sub
End Class
4. メモリ管理の極限:DisposeとGCの制御
VB.NETにおいて「フォームを閉じる」ことは、必ずしも「メモリを解放する」ことと同義ではない。特にWindows API(`SendMessage`等)をフックしている場合、`Dispose` を呼び出してもアンマネージリソースが残留することがある。
- 明示的Disposeの徹底: `IDisposable` を実装し、`Components` コレクションの破棄を確実に行う。
- GCの強制介入を避ける: `GC.Collect()` を安易に呼ぶのは素人の所業だ。オブジェクトのスコープを最小化し、不要な参照(特にイベントハンドラ)を `RemoveHandler` で切断することで、ガベージコレクタに「いつ掃除すべきか」を正しく教えるのがプロの仕事である。
‘ フォーム破棄時のイベントハンドラ切断(メモリリーク対策)
Private Sub Form2_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
‘ 購読しているイベントをすべて解除
RemoveHandler _service.DataChanged, AddressOf OnDataChanged
‘ アンマネージリソースの解放
‘ 必要に応じて、ここでMarshal.ReleaseComObject等を行う
End Sub
5. 結論:UIを「使い捨てのパーツ」にする
このアーキテクチャの最大の利点は、「Form2が壊れても、Form1には一切の影響がない」という点にある。開発者はインターフェイスを実装するだけで、複雑な遷移ロジックをNavigatorに投げることができる。
レガシーなVB.NET環境であっても、構造を変えるだけでパフォーマンスと保守性は劇的に改善する。
- 密結合を断つ: `New` キーワードを避ける。
- DIを活用する: 画面生成はコンテナかファクトリに一任する。
- イベントを管理する: フォームを閉じる際は、必ず `RemoveHandler` で紐付けを断つ。
これが、我々アーキテクトが辿り着いた「Windows Formsを延命させ、かつ進化させるための唯一の解」である。コードは芸術ではない。極めて実用的で、冷徹なまでの論理の積み重ねであるべきだ。さあ、今すぐあなたのプロジェクトの `Form.Show()` を検索し、その呪縛を解き放て。
