Factory Method (ファクトリメソッド) パターン
インスタンス生成を Factory(工場)に任せるデザインパターンです。
「普通に new すればいいじゃん」と思われるかもしれませんが、
new する前やした後に、あれやこれややって、やっとメインロジックで使える形になるクラスだとしたら?
メインロジックの色々な所で、一々それをやるのは嫌ですよね。
また、 Factory(工場)によって、抽象化されたオブジェクトを生産してもらい、
メインロジックはあくまでも、実際に中に入っている具象オブジェクトの生成過程を意識せず、
その抽象化されたオブジェクトを扱う様にコーディングしておけば、例え生成過程が変わったとしても
メインロジックの修正は必要なくなってしまうわけです。あら便利。
■クラス図
ここで用いるサンプルのクラス図です。
準備中...
■サンプルの説明

ComboBox を選択し、生産ボタンをクリックすると、ComboBox の選択値に応じて、
コントロールを作成し、画面に表示します。
サンプルのプロジェクトダウンロード
■コード
アプリケーションのエントリポイント StartUpForm です。
生産ボタンをクリックすると、ComboBox の選択値に応じて Factory(工場)を生成し、
Factory(工場)の生産したモノをForm に表示します。
Public Class StartUpForm Inherits System.Windows.Forms.Form #Region " Windows フォーム デザイナで生成されたコード " Public Sub New() MyBase.New() ' この呼び出しは Windows フォーム デザイナで必要です。 InitializeComponent() ' InitializeComponent() 呼び出しの後に初期化を追加します。 AddHandler Application.ThreadException, AddressOf CommonExceptionAndHandler.ExceptionHandler.MyHandler End Sub ' Form は、コンポーネント一覧に後処理を実行するために dispose をオーバーライドします。 Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub ' Windows フォーム デザイナで必要です。 Private components As System.ComponentModel.IContainer ' メモ : 以下のプロシージャは、Windows フォーム デザイナで必要です。 'Windows フォーム デザイナを使って変更してください。 ' コード エディタを使って変更しないでください。 Friend WithEvents Label1 As System.Windows.Forms.Label Friend WithEvents ComboBox1 As System.Windows.Forms.ComboBox Friend WithEvents Button1 As System.Windows.Forms.Button Friend WithEvents Panel1 As System.Windows.Forms.Panel <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() Me.Label1 = New System.Windows.Forms.Label Me.ComboBox1 = New System.Windows.Forms.ComboBox Me.Button1 = New System.Windows.Forms.Button Me.Panel1 = New System.Windows.Forms.Panel Me.SuspendLayout() ' 'Label1 ' Me.Label1.Location = New System.Drawing.Point(8, 8) Me.Label1.Name = "Label1" Me.Label1.TabIndex = 0 Me.Label1.Text = "Label1" ' 'ComboBox1 ' Me.ComboBox1.Location = New System.Drawing.Point(104, 8) Me.ComboBox1.Name = "ComboBox1" Me.ComboBox1.Size = New System.Drawing.Size(104, 20) Me.ComboBox1.TabIndex = 1 Me.ComboBox1.Text = "ComboBox1" ' 'Button1 ' Me.Button1.Location = New System.Drawing.Point(208, 8) Me.Button1.Name = "Button1" Me.Button1.TabIndex = 4 Me.Button1.Text = "Button1" ' 'Panel1 ' Me.Panel1.Location = New System.Drawing.Point(8, 40) Me.Panel1.Name = "Panel1" Me.Panel1.Size = New System.Drawing.Size(272, 216) Me.Panel1.TabIndex = 5 ' 'StartUpForm ' Me.AutoScaleBaseSize = New System.Drawing.Size(5, 12) Me.ClientSize = New System.Drawing.Size(292, 266) Me.Controls.Add(Me.Panel1) Me.Controls.Add(Me.Button1) Me.Controls.Add(Me.ComboBox1) Me.Controls.Add(Me.Label1) Me.Name = "StartUpForm" Me.Text = "Form1" Me.ResumeLayout(False) End Sub #End Region '生産する種類 Private Const KIND_COMBO As String = "ComboBox" Private Const KIND_LIST As String = "ListBox" '生産されるモノ(Control)に表示するデータ Private m_dt As DataTable '画面がロードされた時のイベント Private Sub StartUpForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.Text = "Factory Method" Me.Label1.Text = "種類:" Me.ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList Me.ComboBox1.Items.Clear() Me.ComboBox1.Items.Add(Me.KIND_COMBO) Me.ComboBox1.Items.Add(Me.KIND_LIST) Me.ComboBox1.SelectedIndex = 0 Me.Button1.Text = "生産" '生産されるモノ(Control)に表示するデータ Me.m_dt = New DataTable("ゲーム機") Me.m_dt.Columns.Add("Name", GetType(String)) Me.m_dt.Columns.Add("名前", GetType(String)) Me.m_dt.Rows.Add(New String() {"FamilyComputer", "ファミコン"}) Me.m_dt.Rows.Add(New String() {"DiskSystem", "ディスクシステム"}) Me.m_dt.Rows.Add(New String() {"NintendoDS", "ニンテンドーDS"}) End Sub '生産ボタンクリック時のイベント Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click Me.Panel1.Controls.Clear() Dim factory As AbstractListComponentFactory Dim listCtrl As IListComponent If Me.ComboBox1.Text = Me.KIND_COMBO Then factory = New ComboBoxFactory Else factory = New ListBoxFactory End If '生産 listCtrl = factory.Create(Me.m_dt, "名前", "Name") Me.Panel1.Controls.Add(DirectCast(listCtrl, Control)) End Sub End Class
何かを生産する工場です。
外部(継承関係にないクラス)に公開するのは、Create メソッドのみで、
Create メソッド内で、実際の具象オブジェクトを生産するメソッド CreateProduct メソッドを呼んでいます。
'何かのモノを生産する抽象クラス Public MustInherit Class AbstractListComponentFactory '何かのモノを生産するメソッド Public Function Create(ByVal dt As DataTable, _ ByVal displayMember As String, _ ByVal valueMember As String) As IListComponent Dim p As IListComponent p = Me.CreateProduct(dt, displayMember, valueMember) Return p End Function '実際のモノを生産するメソッド定義 Protected MustOverride Function CreateProduct(ByVal dt As DataTable, _ ByVal displayMember As String, _ ByVal valueMember As String) As IListComponent End Class
ComboBox を生産する工場です。
AbstractListComponentFactory を継承しています。
'ComboBox工場 Public Class ComboBoxFactory Inherits AbstractListComponentFactory '実際のモノ(ComboBox)を生産するメソッド実装 Protected Overrides Function CreateProduct(ByVal dt As System.Data.DataTable, _ ByVal displayMember As String, _ ByVal valueMember As String) As IListComponent Dim myComboB As MyComboBox myComboB = New MyComboBox With myComboB .DataSource = dt .DisplayMember = displayMember .ValueMember = valueMember .Location = New System.Drawing.Point(10, 10) .Size = New System.Drawing.Size(240, 20) End With Return myComboB End Function End Class
ListBox を生産する工場です。
AbstractListComponentFactory を継承しています。
'ListBox工場 Public Class ListBoxFactory Inherits AbstractListComponentFactory '実際のモノ(ListBox)を生産するメソッド実装 Protected Overrides Function CreateProduct(ByVal dt As System.Data.DataTable, _ ByVal displayMember As String, _ ByVal valueMember As String) As IListComponent Dim myListB As MyListBox myListB = New MyListBox With myListB .DataSource = dt .DisplayMember = displayMember .ValueMember = valueMember .Location = New System.Drawing.Point(10, 10) .Size = New System.Drawing.Size(240, 150) End With Return myListB End Function End Class
Factory(工場)によって生産される何かを表すインターフェースです。
'Factoryによって生産される何か Public Interface IListComponent Inherits System.ComponentModel.IComponent End Interface
Factory(工場)によって生産される何かの 1 つ、ComboBox です。
IListComponent インターフェースを implement しています。
'ComboBox Public Class MyComboBox Inherits ComboBox Implements IListComponent End Class
Factory(工場)によって生産される何かの 1 つ、ListBox です。
IListComponent インターフェースを implement しています。
'ListBox Public Class MyListBox Inherits ListBox Implements IListComponent End Class
■ひとこと
Templete Method パターン同様、比較的業務で良く使われるデザインパターンです。
ComboBox や ListBox を new した後に、Factory(工場)で色々やってから、メインロジックに渡してくれます。
もし、「携帯ゲーム機については"(携帯)"という文字をおしりに付加して表示する」という仕様変更があったとします。
そして、画面で生成している、DataTable オブジェクトの中身は変えないで欲しいという依頼があったとしたら。
具象の Factory を修正するか、もしくは親クラスの中で 別の DataTable を用意してやる等、
メインロジック以外の箇所で修正が終わってしまうはずです。
似たような名前のデザインパターンに、 Abstract Factory パターンがありますが、
微妙に色々違ってたりします。ちょっと見てみたりして下さい。