Design Pattern

[Design Pattern] 21. Abstract Factory Pattern(추상 팩토리 패턴) C#

o0zrone 2023. 4. 10. 12:40
728x90

어떠한 개체의 관련 객체들의 모음을 생성할 수 있도록 하는 디자인 패턴입니다.

 

생성 패턴(Creational Design Patterns) 중 하나입니다.

 

 

장점

  • 팩토리에서 생성되는 제품들의 상호 호환을 보장할 수 있습니다.
  • 생성되는 클래스들과 기존 코드 사이의 단단한 결합을 피할 수 있습니다.
  • 단일 책임 원칙을 만족하며 생성 코드를 한 곳으로 모아 코드를 더 쉽게 유지보수할 수 있습니다.
  • 개방/폐쇄 원칙을 만족하여 기존 코드를 변경하지 않고 새로운 객체들을 생성할 수 있습니다.

단점

  • 패턴을 적용하기 위해 인터페이스들과 클래스들이 많이 추가되기 때문에 코드가 많이 복잡해질 수 있습니다.

 

C#으로 Console 프로젝트를 하나 생성해서 할 것입니다.

이번엔 Pizza Factory에서 시카고 피자랑 뉴욕피자를 생성하겠습니다.

 

일단 프로젝트의 tree구조는 아래와 같습니다.

AbstractFactory(Project)

|- Program.cs (Main)

|- ICrust.cs (Abstract Product)

|- ThinCrust.cs (Concrete Product)

|- DeepDishCrust.cs (Concrete Product)

|- IPizza.cs (Abstract Product)

|- NewYorkPizza.cs (Concrete Product)

|- ChicagoPizza.cs (Concrete Product)

|- IPizzaFactory.cs (Abstract Factory interface)

|- NewYorkPizzaFactory.cs (Concrete Factory)

|- ChicagoPizzaFactory.cs (Concrete Factory)

 


ICrust.cs

namespace AbstractFactory
{
    public interface ICrust
    {
        void AddSauce();
    }
}

AddSauce를 구성해줍니다.

ThinCrust.cs

using System;

namespace AbstractFactory
{
    public class ThinCrust : ICrust
    {
        public void AddSauce()
        {
            Console.WriteLine("[Thin Pizza] Add sauce");
        }
    }
}

ThinPizza에 소스 추가!

DeepDishCrust.cs

using System;

namespace AbstractFactory
{
    public class DeepDishCrust : ICrust
    {
        public void AddSauce()
        {
            Console.WriteLine("[Deep Dish Pizza] Add a lot of sauce");
        }
    }
}

DeepDishPizza는 잔뜩 추가해 줍니다!

IPizza.cs

namespace AbstractFactory
{
    public interface IPizza
    {
        void AddToppings(params string[] toppings);
    }

}

Pizza에 토핑을 원하는 만큼 추가 할 수 있도록 params로 받아 줍니다.

* params는 가변인자 배열로 개수에 제한 없이 입력받게 해주는 키워드입니다.

NewYorkPizza.cs

using System;

namespace AbstractFactory
{
    public class NewYorkPizza : IPizza
    {
        public void AddToppings(params string[] toppings)
        {
            Console.WriteLine($"[NewYork Pizza] Add {string.Join(", ", toppings)}");
        }
    }
}

구별하기 쉽도록 맨앞에 NewYork Pizza라고 적어주고 입력 받은 매개변수는 Join을 이용해 나열해 줍니다.

ChicagoPizza.cs

using System;

namespace AbstractFactory
{
    public class ChicagoPizza : IPizza
    {
        public void AddToppings(params string[] toppings)
        {
            Console.WriteLine($"[Chicago Pizza] Add {string.Join(", ", toppings)}");
        }
    }
}

이름만 Chicago로 바꿔 뉴욕피자와 동일하게 구현해줍니다.

IPizzaFactory.cs

namespace AbstractFactory
{
    public interface IPizzaFactory
    {
        IPizza CreatePizza();
        ICrust CreateCrust();
    }
}

피자를 생성하는 공장의 틀을 잡아줍니다. 크러스트와 피자를 만들게 구현해 주면 되겠죠?


NewYorkPizzaFactory.cs

namespace AbstractFactory
{
    public class NewYorkPizzaFactory : IPizzaFactory
    {
        public IPizza CreatePizza()
        {
            return new NewYorkPizza();
        }

        public ICrust CreateCrust()
        {
            return new ThinCrust();
        }
    }
}

뉴욕 피자 공장입니다. 뉴욕 피자를 생성해 반환해주고 Thin Crust로 만들어 줍니다.

ChicagoPizzaFactory.cs

namespace AbstractFactory
{
    public class ChicagoPizzaFactory : IPizzaFactory
    {
        public IPizza CreatePizza()
        {
            return new ChicagoPizza();
        }

        public ICrust CreateCrust()
        {
            return new DeepDishCrust();
        }
    }
}

시카고 피자 공장에서는 DeepDish 크러스트로 시카고 피자를 만들어 줍니다.

Program.cs

using System;

namespace AbstractFactory
{
    class Program
    {
        static void Main(string[] args)
        {
            IPizzaFactory newYorkFactory = new NewYorkPizzaFactory();
            IPizzaFactory chicagoFactory = new ChicagoPizzaFactory();

            IPizza newYorkPizza = newYorkFactory.CreatePizza();
            ICrust newYorkCrust = newYorkFactory.CreateCrust();

            IPizza chicagoPizza = chicagoFactory.CreatePizza();
            ICrust chicagoCrust = chicagoFactory.CreateCrust();

            newYorkCrust.AddSauce();
            newYorkPizza.AddToppings("pepperoni");

            Console.WriteLine();

            chicagoCrust.AddSauce();
            chicagoPizza.AddToppings("pepperoni", "minced meat");
        }
    }
}

뉴욕 피자 공장과 시카고 피자 공장을 만들고 각 피자를 생성해 줍니다.

 

그이후에 소스를 뿌리고 토핑을 추가해주면 완성입니다.

아래의 결과를 보시면 원하는 대로 나왔음을 확인 하실 수 있습니다.

실행 결과

 

이 패턴은 유용합니다만 상당히 많은 양의 코드를 요구해서 코드가 복잡해 지지않도록 추가하시는게 좋겠습니다.