記念すべき100エントリ目となりました。いい加減にシリーズ再開せねばということで、前回から間が空きましたが、今回はAbstract Factoryパターンを取り上げます。
Abstract Factoryパターンは、具象クラスに依存することなく、一連の関連するオブジェクトを生成するためのインタフェイスを提供します。
具体的には、例えばGUIインタフェイスでスキンを指定したら、それに紐付くボタン、枠、スクロールバーなどを生成する、といった用途で使われているようですね。
では、コード例です。今回はお弁当の種類に応じたごはんとおかずを作るFactoryをコードにしてみます。
- 生成される製品の抽象クラスを定義します。
public abstract class Abstractごはん
{
public abstract string 名前
{
get;
}
}
public abstract class Abstractおかず
{
public abstract string 名前
{
get;
}
}
Public MustInherit Class Abstractごはん
Public MustOverride ReadOnly Property 名前() As String
End Class
Public MustInherit Class Abstractおかず
Public MustOverride ReadOnly Property 名前() As String
End Class
- 1.で作成した抽象製品クラスを継承し、具象製品クラスを定義します。
public class ごはん : Abstractごはん
{
public override string 名前
{
get { return "ごはん"; }
}
}
public class ふりかけごはん : Abstractごはん
{
public override string 名前
{
get { return "ふりかけごはん"; }
}
}
public class ごま塩ごはん : Abstractごはん
{
public override string 名前
{
get { return "ごま塩ごはん"; }
}
}
public class 梅干し : Abstractおかず
{
public override string 名前
{
get { return "梅干し"; }
}
}
public class から揚げ : Abstractおかず
{
public override string 名前
{
get { return "から揚げ"; }
}
}
public class 玉子焼き : Abstractおかず
{
public override string 名前
{
get { return "玉子焼き"; }
}
}
public class 焼き鮭 : Abstractおかず
{
public override string 名前
{
get { return "焼き鮭"; }
}
}
public class 煮物 : Abstractおかず
{
public override string 名前
{
get { return "煮物"; }
}
}
public class ウインナ : Abstractおかず
{
public override string 名前
{
get { return "ウインナ"; }
}
}
Public Class ごはん
Inherits Abstractごはん
Public Overrides ReadOnly Property 名前() As String
Get
Return "ごはん"
End Get
End Property
End Class
Public Class ふりかけごはん
Inherits Abstractごはん
Public Overrides ReadOnly Property 名前() As String
Get
Return "ふりかけごはん"
End Get
End Property
End Class
Public Class ごま塩ごはん
Inherits Abstractごはん
Public Overrides ReadOnly Property 名前() As String
Get
Return "ごま塩ごはん"
End Get
End Property
End Class
Public Class 梅干し
Inherits Abstractおかず
Public Overrides ReadOnly Property 名前() As String
Get
Return "梅干し"
End Get
End Property
End Class
Public Class から揚げ
Inherits Abstractおかず
Public Overrides ReadOnly Property 名前() As String
Get
Return "から揚げ"
End Get
End Property
End Class
Public Class 玉子焼き
Inherits Abstractおかず
Public Overrides ReadOnly Property 名前() As String
Get
Return "玉子焼き"
End Get
End Property
End Class
Public Class 焼き鮭
Inherits Abstractおかず
Public Overrides ReadOnly Property 名前() As String
Get
Return "焼き鮭"
End Get
End Property
End Class
Public Class 煮物
Inherits Abstractおかず
Public Overrides ReadOnly Property 名前() As String
Get
Return "煮物"
End Get
End Property
End Class
Public Class ウインナ
Inherits Abstractおかず
Public Overrides ReadOnly Property 名前() As String
Get
Return "煮物"
End Get
End Property
End Class
- 1.で作成した抽象クラスそれぞれを生成するメソッド(Factory Method)を持つ、抽象Factoryクラスを定義します。
public abstract class Abstractお弁当Factory
{
public abstract Abstractごはん Createごはん();
public abstract Abstractおかず[] Createおかず();
}
Public MustInherit Class Abstractお弁当Factory
Public MustOverride Function Createご飯() As Abstractごはん
Public MustOverride Function Createおかず() As Abstractおかず()
End Class
- 3.で作成した抽象クラスを継承し、具象Factoryクラスを定義します。
public class 日の丸弁当Factory : Abstractお弁当Factory
{
public override Abstractごはん Createごはん()
{
return new ごはん();
}
public override Abstractおかず[] Createおかず()
{
return new Abstractおかず[] { new 梅干し() };
}
}
public class 和風弁当Factory : Abstractお弁当Factory
{
public override Abstractごはん Createごはん()
{
return new ごま塩ごはん();
}
public override Abstractおかず[] Createおかず()
{
return new Abstractおかず[] {
new 梅干し()
, new 焼き鮭()
, new 煮物()
};
}
}
public class こども弁当Factory : Abstractお弁当Factory
{
public override Abstractごはん Createごはん()
{
return new ふりかけごはん();
}
public override Abstractおかず[] Createおかず()
{
return new Abstractおかず[] {
new ウインナ()
, new 玉子焼き()
, new から揚げ()
};
}
}
Public Class 日の丸弁当Factory
Inherits Abstractお弁当Factory
Public Overrides Function Createご飯() As Abstractごはん
Return New ごはん()
End Function
Public Overrides Function Createおかず() As Abstractおかず()
Return New Abstractおかず() {New 梅干し()}
End Function
End Class
Public Class 和風弁当Factory
Inherits Abstractお弁当Factory
Public Overrides Function Createご飯() As Abstractごはん
Return New ごま塩ごはん()
End Function
Public Overrides Function Createおかず() As Abstractおかず()
Return New Abstractおかず() { _
New 梅干し() _
, New 焼き鮭() _
, New 煮物() _
}
End Function
End Class
Public Class こども弁当Factory
Inherits Abstractお弁当Factory
Public Overrides Function Createご飯() As Abstractごはん
Return New ふりかけごはん()
End Function
Public Overrides Function Createおかず() As Abstractおかず()
Return New Abstractおかず() { _
New ウインナ() _
, New 玉子焼き() _
, New から揚げ() _
}
End Function
End Class
- 1~4.で作成したクラス群を使用する、Clientクラスを定義します。
public class お弁当Client
{
private Abstractごはん ごはん;
private Abstractおかず[] おかず;
private Abstractお弁当Factory お弁当Factory;
public お弁当Client(string 種類)
{
if ( 種類 == "日の丸" )
{
this.お弁当Factory = new 日の丸弁当Factory();
}
else if ( 種類 == "和風" )
{
this.お弁当Factory = new 和風弁当Factory();
}
else if ( 種類 == "こども" )
{
this.お弁当Factory = new こども弁当Factory();
}
}
public void お弁当作成()
{
this.ごはん = お弁当Factory.Createごはん();
this.おかず = お弁当Factory.Createおかず();
}
public override string ToString()
{
List<string> おかず名List = new List<string>();
foreach ( Abstractおかず おかず単品 in おかず )
{
おかず名List.Add(おかず単品.名前);
}
return String.Format(
"{0}におかずとして、{1}が付いています。"
, ごはん.名前
, String.Join("、", おかず名List.ToArray())
);
}
}
Public Class お弁当Client
Private ごはん As Abstractごはん
Private おかず As Abstractおかず()
Private お弁当Factory As Abstractお弁当Factory
Sub New(ByVal 種類 As String)
If 種類 = "日の丸" Then
Me.お弁当Factory = New 日の丸弁当Factory()
ElseIf 種類 = "和風" Then
Me.お弁当Factory = New 和風弁当Factory()
ElseIf 種類 = "こども" Then
Me.お弁当Factory = New こども弁当Factory()
End If
End Sub
Public Sub お弁当作成()
Me.ごはん = Me.お弁当Factory.Createご飯()
Me.おかず = Me.お弁当Factory.Createおかず()
End Sub
Public Overrides Function ToString() As String
Dim おかず名List As New List(Of String)()
For Each おかず単品 As Abstractおかず In Me.おかず
おかず名List.Add(おかず単品.名前)
Next
Return String.Format( _
"{0}におかずとして、{1}が付いています。" _
, ごはん.名前 _
, String.Join("、", おかず名List.ToArray()) _
)
End Function
End Class
上記コードを実行してみます。
実行コード
public class Program
{
static void Main(string[] args)
{
お弁当Client client;
Console.WriteLine("日の丸弁当:");
client = new お弁当Client("日の丸");
client.お弁当作成();
Console.WriteLine(client.ToString());
Console.WriteLine("和風弁当:");
client = new お弁当Client("和風");
client.お弁当作成();
Console.WriteLine(client.ToString());
Console.WriteLine("こども弁当:");
client = new お弁当Client("こども");
client.お弁当作成();
Console.WriteLine(client.ToString());
Console.ReadKey();
}
}
Public Class Program
Public Shared Sub Main(ByVal args As String())
Dim client As お弁当Client
Console.WriteLine("日の丸弁当:")
client = New お弁当Client("日の丸")
client.お弁当作成()
Console.WriteLine(client.ToString())
Console.WriteLine("和風弁当:")
client = New お弁当Client("和風")
client.お弁当作成()
Console.WriteLine(client.ToString())
Console.WriteLine("こども弁当:")
client = New お弁当Client("こども")
client.お弁当作成()
Console.WriteLine(client.ToString())
Console.ReadKey()
End Sub
End Class
実行結果
日の丸弁当:
ごはんにおかずとして、梅干しが付いています。
和風弁当:
ごま塩ごはんにおかずとして、梅干し、焼き鮭、煮物が付いています。
こども弁当:
ふりかけごはんにおかずとして、ウインナ、玉子焼き、から揚げが付いています。
さて、上記のコードをよく見てみると、気付くことがあります。
まずは、3.で定義した抽象Factoryですが、そのメンバである製品を生成するメソッドは、前回紹介したFactory Methodパターンとなっています。
また、Clientクラスの中で、抽象Factoryクラスの変数に、具象Factoryのインスタンスを切り替えて設定し、Factoryメソッドを実行している箇所は、Strategyパターンになっていますね。(この辺の話は以前凪瀬さんがまとめていらっしゃいますのでご一読をオススメします。)
このように、あるパターンの中に他のパターンが紛れている、ということもGoFパターンにはちょくちょくあるようですので、その意味、役割を考えなければいけませんね。わたしももう少し勉強します(^^;
さて、次回はFactoryパターンについてのまとめをお送りする予定です。