추상 팩토리 패턴

정선호·2023년 5월 10일
0

Design Patterns

목록 보기
9/24

관련 영상

추상 팩토리

위키피디아
추상 팩토리 패턴

  • 관련 객체들의 구상 클래스들을 지정하지 않고도 관련 객체들의 모음을 생성할 수 있도록 하는 생성패턴
  • 다양한 구성 요소 별로 '객체의 집합'을 생성해야 할 때 유용하다. 이 패턴을 사용하여 상황에 알맞은 객체를 생성할 수 있다.

추상 팩토리의 구조

  • 추상 제품들(Abstract Products)
    • 제품 패밀리를 구성하는 개별 연관 제품들의 집합에 대한 인터페이스들을 선언
  • 구상 재품들(Concrete Products)
    • 변형들로 그룹화된 추상 제품들의 다양한 구현들
    • 각 추상 제품은 주어진 모든 변형에 구현되어야 함
  • 추상 팩토리(Abstract Factory)
    • 각각의 추상 제품들을 생성하기 위한 여러 메서드들의 집합을 선언
  • 구상 팩토리(Concrete Factory)
    • 추상 팩토리의 생성 메서드들 구현
    • 각 구상 팩토리는 제품들의 특정 변형들에 해당하며 해당 특정 변형들만 생성함
  • 구상 팩토리들은 구상 제품들을 인스턴스화하거나, 그 제품들의 생성 메서드들의 시그지처들은 그에 해당하는 추상 제품들을 반환해야 함. 그래야 팩토리를 사용하는 클라이언트 코드가 팩토리에서 받은 제품의 특정 변형과 결합되지 않음
  • 클라이언트는 추상 인터페이스를 통해 팩토리/제품 변형의 객체들과 소통하는 한 그 어떤 구상 팩토리/제품 변형과 작업할 수 있음. 그래야 팩토리를 사용하는 클라이언트 코드가 팩토리에서 받은 제품의 특정 변형과 결합되지 않음
  • 클라이언트는 추상 인터페이스를 통해 팩토리/제품 변형의 객체들과 소통하는 한 그 어떤 구상 팩토리/제품 변형과 작업할 수 있음

추상 팩토리의 적용

  • 관련된 제품군의 다양한 패밀리들과 작동해야 하지만, 해당 제품들의 구상 클래스들에 의존하고 싶지 않을 때
    • 이러한 클래스들은 미리 알려지지 않았을 수 있으며, 그 때문에 향후 확장성을 허용하기를 원할 수 있다.
  • 코드에 클래스가 있고 이 클래스의 팩토리 메서드들의 집합의 기본 책임이 뚜렷하지 않을 때
    • 잘 설계된 프로그램에서는 각 클래스는 하나의 책임만 가진다. 클래스가 여러 제품 유형을 상대할 경우, 클래스의 팩토리 메서드들을 독립실행형 팩토리 클래스 또는 완전한 추상 팩토리 구현으로 구현할 가치가 있다.

다른 패턴과의 관계

  • 많은 디자인은 복잡성이 낮고 자식 클래스들을 통해 더 많은 커스터마이징이 가능한 팩토리 메서드로 시작해 더 유연하면서도 더 복잡한 추상 팩토리, 프로토타입 또는 빌더 패턴으로 발전해 나간다.
  • 빌더는 복잡한 객체들을 단계별로 생성하는 데 중점을 둔다. 추상 팩토리는 관련된 객체들의 패밀리들을 생성하는 데 중점을 둔다. 추상 팩토리는 제품을 즉시 반환하지만 빌더는 제품을 가져오기 전에 당신이 몇 가지 추가 생성 단계들을 실행할 수 있도록 한다.
  • 추상 팩토리 클래스들은 팩토리 메서드들의 집합을 기반으로 하는 경우가 많다. 그러나 프로토타입을 사용하여 추상 팩토리의 구상 클래스들의 생성 메서드들을 구현할 수도 있다.
  • 추상 팩토리는 하위시스템 객체들이 클라이언트 코드에서 생성되는 방식만 숨기고 싶을 때 퍼사드 대신 사용할 수 있다.
  • 추상 팩토리를 브리지와 함께 사용할 수 있다. 이 조합은 브리지에 의해 정의된 어떤 추상화들이 특정 구현들과만 작동할 수 있을 때 유용하다. 이런 경우에 추상 팩토리는 이러한 관계들을 캡슐화하고 클라이언트 코드에서부터 복잡성을 숨길 수 있다.
  • 추상 팩토리들, 빌더들 및 프로토타입들은 모두 싱글턴으로 구현할 수 있다.

추상 팩토리로 구현한 테란 유닛 생성과 확장

  • 추상 제품들
    • 유닛 생성과 인구 확장에 관한 추상 클래스
public abstract class UnitBuilding : MonoBehaviour
{
    public abstract void produce();
}

public abstract class RaceCapacity : MonoBehaviour
{
    public abstract void expand();
}
  • 콘크리트 제품들
    • 생성할 유닛과 확장할 인구 대상이 상세하게 구현된 클래스
public class Barracks : UnitBuilding {

	public override void produce()
	{
        Debug.Log("Terran Unit 생산 !!!");
    }
}

public class Gateway : UnitBuilding {

	public override void produce()
	{
        Debug.Log("Protoss Unit 생산 !!!");
  }
}

public class SupplyDepot : RaceCapacity {

	public override void expand()
	{
        Debug.Log("Terran Capacity +8 !!!");
    }
}

public class Pylon : RaceCapacity {

	public override void expand()
	{
        Debug.Log("Protoss Capacity +8 !!!");
    }
}
  • 추상 팩토리
    • 구현할 제품들을 출하할 함수들의 원형 선언
public enum Race
{
    Terran,
    Protoss,
    Zerg
}

public abstract class RaceFactory : MonoBehaviour
{
    public abstract GameObject makeCapacityBuilding();
    public abstract GameObject makeUnitBuilding();
}
  • 콘크리트 팩토리
    • 실제로 제품들을 출하하는 로직을 구현한 클래스
public class TerranFactory : RaceFactory
{
    public GameObject supply;
    public GameObject barracks;

    public override GameObject makeCapacityBuilding()
    {
        //return new SupplyDepot();
        return Instantiate(supply, new Vector3(-1.0f, 1.0f, 0.0f), Quaternion.identity);
    }

    public override GameObject makeUnitBuilding()
    {
        //return new Barracks();
        return Instantiate(barracks, new Vector3(1.0f, 0.5f, 0.0f), Quaternion.identity);
    }
}

public class ProtossFactory : RaceFactory
{
    public GameObject pylon;
    public GameObject gateway;

    public override GameObject makeCapacityBuilding()
    {
        //return new Pylon();
        return Instantiate(pylon, new Vector3(-1.0f, 1.0f, 0.0f), Quaternion.identity);
    }

    public override GameObject makeUnitBuilding()
    {
        //return new Gateway();
        return Instantiate(gateway, new Vector3(1.0f, 0.5f, 0.0f), Quaternion.identity);
    }
}
  • 이들을 한데 통합하여 클라이언트에 선언해줄 최종 팩토리
public class FactoryMethod : MonoBehaviour {

	public Race type = Race.Terran;

	public RaceFactory getFactory()
	{
        RaceFactory factory = null;

		switch (type)
		{
		case Race.Terran:
			//factory = new TerranFactory ();
			factory = GetComponent<TerranFactory>();
			break;
		case Race.Protoss:
			//factory = new ProtossFactory();
			factory = GetComponent<ProtossFactory>();
			break;
		}

		return factory;
	}
}
  • 팩토리를 사용하는 클라이언트
public class FactoryMethodUse : MonoBehaviour {

    RaceFactory factory = null;

	void Start () {
		factory = GetComponent<FactoryMethod>().getFactory();

		GameObject capacity = factory.makeCapacityBuilding();
		GameObject building = factory.makeUnitBuilding();

    capacity.GetComponent<RaceCapacity>().expand();
		building.GetComponent<UnitBuilding>().produce();
  }
}

추상 팩토리로 구현한 자동차 공장

Github 링크

profile
학습한 내용을 빠르게 다시 찾기 위한 저장소

1개의 댓글

comment-user-thumbnail
2024년 1월 31일

많은 도움이 되었습니다. 감사해요

답글 달기