6. Facade Pattern (퍼사드 패턴 C# )

|

[읽기전에]

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

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



<기본 정의 >


1. Facade Pattern 정의


  -어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공합니다. 퍼사드에서 고수준 인터페이스를

   정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있습니다.

   (Provide a unified interface to a set of interfaces in a subsystem. 

    Façade defines a higher-level interface that makes the subsystem easier to use.)


 -복잡한 내부처리 내용을 일괄적으로 처리해준다. 외부에는 간단한 인터페이스만 노출됨.

 


2. UML Diagram





3. 사용용도 및 장점


 -하나의 시스템에서 하나의 작업을 처리하는데 여러개의 클래스의 상호 동작이 필요할때, 이것을 묶어서 처리

   하며 외부에는 간단한 인터페이스로 노출한다.


 -컴퓨터 시스템을 예를들면, 컴퓨터를 켜면 컴퓨터에서는 자체적으로 CPU를 가동/바이오스 로드/램초기화/OS시동

  등을 일련의 작업을 하게된다. 사용자는 단순히 컴퓨터의 본체의 POWER만 켰을뿐인데 내부적으로는 여러가지의

  일들이 정해진 순서로 일어나게 된다. 또한 파워를 끌때도 일련의 종료작업 및 하드웨어 종료 작업이 순차적으로 진행

  되는데 이때도 사용자는 단지 컴퓨터 종료만 하면 모든게 자동으로 처리된다.

  이런 시스템에서 사용이 가능한다.


 -사용자는 복잡한 내부절차를 알지 못해도 단순한 인퍼페이스로 시스템을 사용이 가능하다.



4. 소스

using System;
 
namespace DoFactory.GangOfFour.Facade.Structural
{
  /// <summary>
  /// MainApp startup class for Structural
  /// Facade Design Pattern.
  /// </summary>
  class MainApp
  {
    /// <summary>
    /// Entry point into console application.
    /// </summary>
    public static void Main()
    {
      Facade facade = new Facade();
 
      facade.MethodA();
      facade.MethodB();
 
      // Wait for user
      Console.ReadKey();
    }
  }
 
  /// <summary>
  /// The 'Subsystem ClassA' class
  /// </summary>
  class SubSystemOne
  {
    public void MethodOne()
    {
      Console.WriteLine(" SubSystemOne Method");
    }
  }
 
  /// <summary>
  /// The 'Subsystem ClassB' class
  /// </summary>
  class SubSystemTwo
  {
    public void MethodTwo()
    {
      Console.WriteLine(" SubSystemTwo Method");
    }
  }
 
  /// <summary>
  /// The 'Subsystem ClassC' class
  /// </summary>
  class SubSystemThree
  {
    public void MethodThree()
    {
      Console.WriteLine(" SubSystemThree Method");
    }
  }
 
  /// <summary>
  /// The 'Subsystem ClassD' class
  /// </summary>
  class SubSystemFour
  {
    public void MethodFour()
    {
      Console.WriteLine(" SubSystemFour Method");
    }
  }
 
  /// <summary>
  /// The 'Facade' class
  /// </summary>
  class Facade
  {
    private SubSystemOne _one;
    private SubSystemTwo _two;
    private SubSystemThree _three;
    private SubSystemFour _four;
 
    public Facade()
    {
      _one = new SubSystemOne();
      _two = new SubSystemTwo();
      _three = new SubSystemThree();
      _four = new SubSystemFour();
    }
 
    public void MethodA()
    {
      Console.WriteLine("\nMethodA() ---- ");
      _one.MethodOne();
      _two.MethodTwo();
      _four.MethodFour();
    }
 
    public void MethodB()
    {
      Console.WriteLine("\nMethodB() ---- ");
      _two.MethodTwo();
      _three.MethodThree();
    }
  }
}


5. 실행결과


MethodA() ----

SubSystemOne Method

SubSystemTwo Method

SubSystemFour Method


MethodB() ----

SubSystemTwo Method

SubSystemThree Method




< 실제 적용 >


1. UML Diagram





2. 사용용도 및 장점


 -퍼사드는 자주사용되는 패턴이다. 스타크래프트에서는 유닛생성에 관련된 예를 들어 보겠습니다

.

 -테란진영을 선택한 게이머가 탱크를 생성할때 우선 미네랄이 탱크를 생성하기에 충분이 있는지 확인을 하며,

  그후에 가스가 충분한지를 확인한다. 그 이후에 밥집(서플라이디폿..유닛생성갯수를 늘려주는 건물)이 부족한지

  확인후에 유닛을 생성하게 된다. 이때 이런 일련의 작업들 UnitCreatable이라는 클래스에서 외부로 노출되는 

  Createable()이란 메소드를 노출시켜서 3가지의 작업의 결과를 한번에 처리하게 된다.


 -유닛을 생성할때마다 꼭하는 작업이기 때문에 그때마다 이런 작업들을 각각 3개를 호출에서 처리하는 것 보다

  하나로 묶어서 처리되는 것이 효율적이다. 그리고 나중이라도 유닛생성에 관련된 기능이 업데이트 된다 하더라도

  UnitCreateable에서만 수정이 되면 다른곳에서는 작업이 필요없게 된다.

 


3. 소스

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Facade
{
    class Program
    {

        static void Main(string[] args)
        {
            UnitCreateable unitCreateable = new UnitCreateable();


            if (unitCreateable.isUnitCreateable(50, 30, 2).Equals(true))
                Console.WriteLine("유닛 생성 가능!");
            else
                Console.WriteLine("유닛 생성 불가능!");

            if (unitCreateable.isUnitCreateable(50, 130, 2).Equals(true))
                Console.WriteLine("유닛 생성 가능!");
            else
                Console.WriteLine("유닛 생성 불가능!");

            if (unitCreateable.isUnitCreateable(50, 30, 5).Equals(true))
                Console.WriteLine("유닛 생성 가능!");
            else
                Console.WriteLine("유닛 생성 불가능!");
           
            Console.ReadKey();

        }

        public class UnitCreateable
        {

            Mineral mineral = new Mineral();
            Gas gas = new Gas();
            UnitLimit unitLimit = new UnitLimit();

            public bool isUnitCreateable(int unitMineralCost, int unitGasCost, int unitLimitCost)
            {
                if (!mineral.isEnoughMineal(unitMineralCost))
                {
                    return false;
                }
                else if (!gas.isEnoughGas(unitGasCost))
                {
                    return false;
                }
                else if (!unitLimit.isEnoughLimit(unitLimitCost))
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }


        class Mineral
        {
            private int mineral = 100;
           
            public bool isEnoughMineal(int unitMineralCost)
            {
                if (unitMineralCost <= mineral)
                    return true;
                else
                    return false;
            }

        }

        class Gas
        {
            private int gas = 100;

            public bool isEnoughGas(int unitGasCost)
            {
                if (unitGasCost <= gas)
                    return true;
                else
                    return false;
            }
        }

        class UnitLimit
        {
            private int limit = 3;

            public bool isEnoughLimit(int unitLimitCost)
            {
                if (unitLimitCost <= limit)
                    return true;
                else
                    return false;
            }

        }

    }
}

 -예제에서는 편의를 위에서 미네랄이나 가스, 유닛제한이 각각의 클래스에서 멤버변수로 선언이 되어있다.

   실제로는 전역변수로 설정된 싱글톤에서 현재의 미네랄,가스,유닛제한의 값을 읽어와서 비교가 되어야 한다.

   또한, 생성후에는 생성된 자원만큼 감소가 되어야한다.



4. 실행결과




5. 피드백


 -퍼사드란 이름만 어렵지 패턴은 단순하네요...



[참조]

 -http://www.dofactory.com

 -Head First Design Patterns

And