まさるblog

越後在住子持ちプログラマー奮闘記 - Author:まさる(高野 将、TAKANO Sho)

目次

Blog 利用状況

ニュース

著書

2010/7発売


Web掲載記事

@IT

.NET開発を始めるVB6プログラマーが知るべき9のこと

CodeZine

実例で学ぶASP.NET Webフォーム業務アプリケーション開発のポイント

第1回 3層データバインドを正しく活用しよう(前編)

ブログパーツ


書庫

日記カテゴリ

コミュニティ

デザインパターンを学ぶ~その16:Factoryパターン(3)~

記念すべき100エントリ目となりました。いい加減にシリーズ再開せねばということで、前回から間が空きましたが、今回はAbstract Factoryパターンを取り上げます。

 

Abstract Factoryパターンは、具象クラスに依存することなく、一連の関連するオブジェクトを生成するためのインタフェイスを提供します。

具体的には、例えばGUIインタフェイスでスキンを指定したら、それに紐付くボタン、枠、スクロールバーなどを生成する、といった用途で使われているようですね。

 

では、コード例です。今回はお弁当の種類に応じたごはんとおかずを作るFactoryをコードにしてみます。

  1. 生成される製品の抽象クラスを定義します。
    C# Code
    public abstract class Abstractごはん
    {
      public abstract string 名前
      {
        get;
      }
    }
    
    public abstract class Abstractおかず
    {
      public abstract string 名前
      {
        get;
      }
    }
    
    VB Code
    Public MustInherit Class Abstractごはん
    
      Public MustOverride ReadOnly Property 名前() As String
    
    End Class
    
    Public MustInherit Class Abstractおかず
    
      Public MustOverride ReadOnly Property 名前() As String
    
    End Class
    
  2. 1.で作成した抽象製品クラスを継承し、具象製品クラスを定義します。
    C# Code
    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 "ウインナ"; }
      }
    }
    
    VB Code
    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
    
  3. 1.で作成した抽象クラスそれぞれを生成するメソッド(Factory Method)を持つ、抽象Factoryクラスを定義します。
    C# Code
    public abstract class Abstractお弁当Factory
    {
      public abstract Abstractごはん Createごはん();
      public abstract Abstractおかず[] Createおかず();
    }
    
    VB Code
    Public MustInherit Class Abstractお弁当Factory
    
      Public MustOverride Function Createご飯() As Abstractごはん
      Public MustOverride Function Createおかず() As Abstractおかず()
    
    End Class
    
  4. 3.で作成した抽象クラスを継承し、具象Factoryクラスを定義します。
    C# Code
    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 から揚げ()
        };
      }
    }
    
    VB Code
    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
    
  5. 1~4.で作成したクラス群を使用する、Clientクラスを定義します。
    C# Code
    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())
          );
      }
    }
    
    VB Code
    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
    

上記コードを実行してみます。

実行コード

C# Code
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();
  }
}
VB Code
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パターンについてのまとめをお送りする予定です。

投稿日時 : 2008年2月27日 23:58

Feedback

# デザインパターンを学ぶ~その17:Factoryパターン(4)~ 2008/05/31 22:23 まさるblog

デザインパターンを学ぶ~その17:Factoryパターン(4)~

タイトル
名前
Url
コメント