3. Abstract Factory Pattern ( 추상 팩토리 패턴 C# )

|

[읽기전에]

  UML 다이어그램 : UML클래스 다이어그램 기본상식 http://hongjinhyeon.tistory.com/25 

  포스팅되는 디자인 패턴의 예는 스타크래프트를 기본으로 하였습니다 : 디자인 패턴을 시작하며 http://hongjinhyeon.tistory.com/24


<기본 정의 >

1. Abstract Factory Pattern 정의

 - 구체적인 클래스를 명시하지 않고도 연관되어 있거나 의존적인 객체 패밀리 생성을 위한 인터페이스 제공.

   (Provide an interface for creating families of related or dependent objects without specifying their concrete classes.)

 

 - 예를 들어서,  곰 세마리 가족(아빠,엄마,아기) 에 대한 대화형 어플리케이션을 개발한다고 했을때에 그 어플리케이션에서

   두가지 종류의 곰(골든베어가족과 브라운베어가족)을 사용자가 선택해서 이야기를 진행하는 기능이 있다면 사용자의 선택

   에 따라서 자동으로 하나의 종류의 아빠 엄마 아기가 생성되어야 한다. 그때 골든베어를 선택하면 자동으로  GoldenDadBear,

   GoldenMomBear, GoldenBabyBear 를 생성해주고 반대로 브라운을 선택하면 BrownDadBear, BrownMomBear, BrownBabyBear 

   을 생성해주어야 한다. 


- 즉, 비슷한 기능을 하지만 종류가 다른 클래스들을 생성하는 인터페이스 제공한다.


2.UML Diagram



3. 사용 용도 및 장점

 -Factory Method Pattern의 장점을 거의 동일하게 가진다.

   ①객체의 생성을 한군데에서 관리를 할수가 있다. (ConcreteCreator 부분에서만 생성코드를 넣는다. )

   ②동일한 인터페이스 구현으로 새로운 객체가 추가되더라도 소스의 수정의 거의 없다. ( 생성 부분의 수정과 신규 클래스의 추가 정도 )

   ③객체를 여러군데에서 생성을 각자하면 동일한 생성을 보장 못하지만, 한군데에서 관리하게 되면 동일한 생성을 보장한다.

 -연관된 객체들을 생성을 할때 실수로 다른종류의 클래스가 생성이 되는것을 방지한다.

 -어플리케이션에서 GUI타입이 여러종류일때, 선택에 따라서 동일한 모양의 GUI타입으로 설정이 된다.


4. 소스

001.using System;
002.  
003.namespace DoFactory.GangOfFour.Abstract.Structural
004.{
005.  /// <summary>
006.  /// MainApp startup class for Structural
007.  /// Abstract Factory Design Pattern.
008.  /// </summary>
009.  class MainApp
010.  {
011.    /// <summary>
012.    /// Entry point into console application.
013.    /// </summary>
014.    public static void Main()
015.    {
016.      // Abstract factory #1
017.      AbstractFactory factory1 = new ConcreteFactory1();
018.      Client client1 = new Client(factory1);
019.      client1.Run();
020.  
021.      // Abstract factory #2
022.      AbstractFactory factory2 = new ConcreteFactory2();
023.      Client client2 = new Client(factory2);
024.      client2.Run();
025.  
026.      // Wait for user input
027.      Console.ReadKey();
028.    }
029.  }
030.  
031.  /// <summary>
032.  /// The 'AbstractFactory' abstract class
033.  /// </summary>
034.  abstract class AbstractFactory
035.  {
036.    public abstract AbstractProductA CreateProductA();
037.    public abstract AbstractProductB CreateProductB();
038.  }
039.  
040.  
041.  /// <summary>
042.  /// The 'ConcreteFactory1' class
043.  /// </summary>
044.  class ConcreteFactory1 : AbstractFactory
045.  {
046.    public override AbstractProductA CreateProductA()
047.    {
048.      return new ProductA1();
049.    }
050.    public override AbstractProductB CreateProductB()
051.    {
052.      return new ProductB1();
053.    }
054.  }
055.  
056.  /// <summary>
057.  /// The 'ConcreteFactory2' class
058.  /// </summary>
059.  class ConcreteFactory2 : AbstractFactory
060.  {
061.    public override AbstractProductA CreateProductA()
062.    {
063.      return new ProductA2();
064.    }
065.    public override AbstractProductB CreateProductB()
066.    {
067.      return new ProductB2();
068.    }
069.  }
070.  
071.  /// <summary>
072.  /// The 'AbstractProductA' abstract class
073.  /// </summary>
074.  abstract class AbstractProductA
075.  {
076.  }
077.  
078.  /// <summary>
079.  /// The 'AbstractProductB' abstract class
080.  /// </summary>
081.  abstract class AbstractProductB
082.  {
083.    public abstract void Interact(AbstractProductA a);
084.  }
085.  
086.  
087.  /// <summary>
088.  /// The 'ProductA1' class
089.  /// </summary>
090.  class ProductA1 : AbstractProductA
091.  {
092.  }
093.  
094.  /// <summary>
095.  /// The 'ProductB1' class
096.  /// </summary>
097.  class ProductB1 : AbstractProductB
098.  {
099.    public override void Interact(AbstractProductA a)
100.    {
101.      Console.WriteLine(this.GetType().Name +
102.        " interacts with " + a.GetType().Name);
103.    }
104.  }
105.  
106.  /// <summary>
107.  /// The 'ProductA2' class
108.  /// </summary>
109.  class ProductA2 : AbstractProductA
110.  {
111.  }
112.  
113.  /// <summary>
114.  /// The 'ProductB2' class
115.  /// </summary>
116.  class ProductB2 : AbstractProductB
117.  {
118.    public override void Interact(AbstractProductA a)
119.    {
120.      Console.WriteLine(this.GetType().Name +
121.        " interacts with " + a.GetType().Name);
122.    }
123.  }
124.  
125.  /// <summary>
126.  /// The 'Client' class. Interaction environment for the products.
127.  /// </summary>
128.  class Client
129.  {
130.    private AbstractProductA _abstractProductA;
131.    private AbstractProductB _abstractProductB;
132.  
133.    // Constructor
134.    public Client(AbstractFactory factory)
135.    {
136.      _abstractProductB = factory.CreateProductB();
137.      _abstractProductA = factory.CreateProductA();
138.    }
139.  
140.    public void Run()
141.    {
142.      _abstractProductB.Interact(_abstractProductA);
143.    }
144.  }
145.}

-Client 클래스의 생성자에서 AbstractFactory 객체를 받아서 실제  AbstractProductA, AbstractProductB 를 생성한다.


5.실행결과

 ProductB1 interacts with ProductA1

 ProductB2 interacts with ProductA2


<실제 적용>

1. UML Diagram



2. 사용 용도 및 장점

 -사용자가 선택한 종족(테란, 프로토스, 저그 )에 따라서 생성할 수 있는 빌딩들을 설정할 수 있다.

 -보통 종족마다 비슷한 종류의 기능을 하는 건물들이 70~80프로는 비슷하다. 이때 추상팩토리 패턴을 이용해서 구현이 가능하다.

 -GUI 설정(지도위에 테두리, 마우스 포인터 등등)도 AbstractProduct로 하나더 생성해서 추가하면 된다.

 -추상팩토리를 이용하면 테란이 인구확장으로 파일런을 생성하는 경우는 없앨수 있다.


3. 소스

001.using System;
002.using System.Collections.Generic;
003.using System.Linq;
004.using System.Text;
005. 
006.namespace AbstractFactory
007.{
008.    class Program
009.    {
010.          static void Main(string[] args)
011.          {
012.              Race _race1 = new Terran();
013.              Game _game1 = new Game(_race1);
014.              _game1.Show();
015. 
016.              Race _race2 = new Protoss();
017.              Game _game2 = new Game(_race2);
018.              _game2.Show();
019. 
020.            Console.ReadKey();
021.         }
022. 
023.          #region 추상 팩토리 설정
024. 
025.          abstract class Race
026.          {
027.              public abstract MaincenterBuilding CreateMaincenterBuilding();
028.              public abstract PopulationBuilding CreatePopulationBuilding();
029.          }
030.  
031.          
032.          class Terran : Race
033.          {
034.            public override MaincenterBuilding CreateMaincenterBuilding()
035.            {
036.                return new CommandCenter();
037.            }
038.            public override PopulationBuilding CreatePopulationBuilding()
039.            {
040.                return new SupplyDepot();
041.            }
042. 
043.          }
044.          
045.          class Protoss : Race
046.          {
047.            public override MaincenterBuilding CreateMaincenterBuilding()
048.            {
049.                return new Nexus();
050.            }
051.            public override PopulationBuilding CreatePopulationBuilding()
052.            {
053.                return new Pylon();
054.            }
055.          }
056. 
057.          #endregion
058. 
059.          #region 추상 Product 클래스 생성
060. 
061.          abstract class MaincenterBuilding
062.          {
063.          }
064.  
065.          abstract class PopulationBuilding
066.          {
067.              public abstract void Interact(MaincenterBuilding a);
068.          }
069. 
070.          #endregion
071. 
072.          #region Product 클래스 생성
073. 
074.          class CommandCenter : MaincenterBuilding
075.          {
076.          }
077. 
078.          class SupplyDepot : PopulationBuilding
079.          {
080.            public override void Interact(MaincenterBuilding a)
081.            {
082.              Console.WriteLine(this.GetType().Name +
083.                " interacts with " + a.GetType().Name);
084.            }
085.          }
086. 
087.          class Nexus : MaincenterBuilding
088.          {
089.          }
090.  
091.          class Pylon : PopulationBuilding
092.          {
093.             public override void Interact(MaincenterBuilding a)
094.            {
095.              Console.WriteLine(this.GetType().Name +
096.                " interacts with " + a.GetType().Name);
097.            }
098.          }
099. 
100.          #endregion
101. 
102. 
103.          class Game
104.          {
105.              private MaincenterBuilding _maincenterBuilding;
106.              private PopulationBuilding _populationBuilding;
107.  
108.             
109.             public Game(Race _race)
110.             {
111.                _maincenterBuilding = _race.CreateMaincenterBuilding();
112.                _populationBuilding = _race.CreatePopulationBuilding();
113.             }
114.  
115.             public void Show()
116.             {
117.                _populationBuilding.Interact(_maincenterBuilding);
118.             }
119.          }
120. 
121.    }
122.}

4. 결과


5. 피드백

 -Factory Method 패턴과 비슷하지만 그것과는 다르게 연관된 클래스들을(family) 생성한다.

 -위의 다이어그램에서 저그가 추가될 시에는 클래스 3개가 추가되고 Game에서 해당 저그를 생성해서 사용해주면 된다.


[참조]

   -Professional VB.NET 디자인 패턴

   -http://www.dofactory.com



And