추상 팩토리 패턴 정의
=> 관련성 있는 여러 종류의 객체를 특정 그룹으로 묶어 한번에 일괄된 방식으로 생성하고 교체할 수 있는 패턴
=> 팩토리 메서드 패턴과 유사하나 객체 생성 메서드 구현 후 하나의 객체를 반환하지만 추상 팩토리 패턴은 연관된 객체들의 패밀리를 반환한다.
장점
=> 1. 관리 용이성 - 클래스 이름 대신 팩토리 메소드를 사용해 객체를 생성하므로 추후 실제 생성되는 객체가 바뀌거나 추가되어 문제가 없다.
=> 2. 보안성 - 클래스의 대부분의 내용은 숨기고 싶을 때, 인터페이스나 abstract를 통해서만 객체에 접근하게 할 수 있다.
=> 3. 리소스 재활용성 - 팩토리 메소드가 반드시 객체를 새로 생성할 필요는 없고, 상황에 따라 새로 생성될수도, 기존의 것을 반환할수도 있다.
=> 4. 위의 세가지 모두 팩토리 메소드 패턴과 같으나, 추상 팩토리 패턴의 경우 팩토리에 상속 구조를 둠으로 세밀한 팩토리 관리가 가능하다.
예를들어, 특정 라이브러리를 배포하는데 OS별로 지원하는 기능이 상이하다면
추상 팩토리 패턴을 이용해 OS별 기능을 통합적으로 변경할 수 있다.
이번에는 스타크래프트에서 종족별로 유닛제한을 증가시키는 건물과 유닛 생산을 해보려고 한다.(물론 로그로)
앞선 팩토리 메소드 패턴으로 이를 구현하려 하면 각 종족별, 건물별, 유닛별 따로 전부 관리를 해야된다.
하지만 추상 팩토리 패턴을 이용하면 특정 그룹(종족)으로 묶어 관리할 수 있게 된다.
프로젝트 정보
// RaceCapacity.cs
using UnityEngine;
public abstract class RaceCapacity
{
public abstract void expend();
}
public class SupplyDepot : RaceCapacity
{
public override void expend()
{
Debug.Log("테란 유닛 제한 + 8");
}
}
public class Pylon : RaceCapacity
{
public override void expend()
{
Debug.Log("프로토스 유닛 제한 + 8");
}
}
먼저 유닛의 제한수를 늘려주는 건물 RaceCapacity.cs이다.
추상 클래스로 expend를 구현해야 한다.
테란과 프로토스의 유닛 제한수를 늘려주는 건물인 SupplyDepot과 Pylon클래스가 상속받아 구현하고 있다.
// UnitBuilding.cs
using UnityEngine;
public abstract class UnitBuilding
{
public abstract void produce();
}
public class Barracks : UnitBuilding
{
public override void produce()
{
Debug.Log("테란 유닛 생산");
}
}
public class GateWay : UnitBuilding
{
public override void produce()
{
Debug.Log("프로토스 유닛 생산");
}
}
다음은 유닛을 생성하는 건물들의 클래스이다.
위와 구조는 같다.
// Factory.cs
public enum Race
{
Terran,
Protoss,
Zerg
}
public abstract class RaceFactory
{
public abstract RaceCapacity makeCapacityBuilding();
public abstract UnitBuilding makeUnitBuilding();
}
public class TerranFactory : RaceFactory
{
public override RaceCapacity makeCapacityBuilding()
{
return new SupplyDepot();
}
public override UnitBuilding makeUnitBuilding()
{
return new Barracks();
}
}
public class ProtossFactory : RaceFactory
{
public override RaceCapacity makeCapacityBuilding()
{
return new Pylon();
}
public override UnitBuilding makeUnitBuilding()
{
return new GateWay();
}
}
각 종족별로 건물들을 묶어 놓았다.
이로써 종족이 달라도 혹은 종족이 무엇인지 몰라도 makeCapacityBuilding을 호출하면
유닛 제한수가 늘어날 것이고
makeUnitBuilding을 호출하면 유닛을 생산하는 건물을 지을것이다.
// FactoryMethod.cs
using UnityEngine;
public class FactoryMethod : MonoBehaviour
{
public Race type = Race.Terran;
public RaceFactory getFactory()
{
RaceFactory factory = null;
switch(type)
{
case Race.Terran:
factory = new TerranFactory();
break;
case Race.Protoss:
factory = new ProtossFactory();
break;
}
return factory;
}
}
다음은 이전 포스팅의 FactoryMethod이다.
이렇게 하고 FactoryUse를 따로 만들면 사용하는 입장에서는
건물이 추가되거나 늘어나도 수정할 필요가 없어진다.
이 코드는 숨겨서 수정이 필요할 때(유닛 추가, 종족 추가 등)만 수정하고 Use로 쓰기만 하면 된다.
// FactoryMethodUse.cs
using UnityEngine;
public class FactoryMethodUse : MonoBehaviour
{
void Start()
{
FactoryMethod factoryMethod = new FactoryMethod();
RaceFactory factory = factoryMethod.getFactory();
RaceCapacity capacity = factory.makeCapacityBuilding();
UnitBuilding building = factory.makeUnitBuilding();
capacity.expend();
building.produce();
}
}
마지막으로 앞에 만든 팩토리 메서드를 사용하는 코드이다.
일단은 로그를 찍으려고 하기 때문에 언제 짓고... 등등의 조건은 하나도 없이
건물을 짓고 로그를 찍어본다.
위의 스크립트들중 FactoryMethodUse.cs만 GameManager에 넣어서 실행해보면 된다.
넣어서 실행해보면 잘 된다.
프로토스로도 테스트를 해보려면 FactoryMethod.cs의 내부에서 타입만 바꿔주면 된다.
항상 말하지만 FactoryMethodUse는 수정할 필요가 없다.
사용하는 입장에서는 종족이 무엇인지 전혀 알 필요가 없다.
프로토스도 잘 실행된다.
저그도 건물 클래스를 만들고 FactoryMethod를 수정하면 똑같이 쓸 수 있다.
위에서 종족별로 건물을 묶어놓았기 때문에
사용하는 입장의 종족이 Terran이라면 모든 건물이 Terran용일 것이다.
그럼 Terran건물만 묶어 놓은 TerranFactory를 쓰면 된다.
이렇게 여러 종류의 객체를 생성할 때 객체들 사이에 규칙이나 관련성이 있는 경우라면
각 종류별로 별도의 Factory클래스를 만드는 것보다 관련 객체들을 묶어 추상 팩토리 패턴을 적용하는게 편리하다.
'프로그래밍 > 디자인 패턴' 카테고리의 다른 글
빌더 패턴 (Builder Pattern) (0) | 2020.05.31 |
---|---|
팩토리 메서드 패턴 (Factory Method Pattern) (0) | 2020.05.26 |
심플 팩토리 패턴 (Simple Factory Pattern) (0) | 2020.05.24 |
스트레티지 패턴 (Strategy Pattern) (0) | 2020.05.20 |
싱글턴 패턴 (Singleton Pattern) (0) | 2020.05.19 |