[c#] 게임으로 이해하는 [생성 패턴] 04 - 빌더(Builder)
RPG 게임에서 캐릭터가 가진 속성을 생각해보자
체력, 방어, 속도, 마나게이지 뿐만 아니라 가지고 있는 기술, 아직 해금되지 않는 기술들도
전부 캐릭터가 가진 속성이다. 이 캐릭터를 생성자로 만든다고 생각해보자.
- 생성자로 캐릭터를 만들 경우
new 캐릭터1("전사", "근접", 100, 50, 20, 150, ...);
이런식으로 생성할텐데, 일단 생성자에 너무 많은 매개변수가 포함되고, 속성의 순서를 기억하기가 어렵다!
이 코드를 만든 당사자면 이해할 순 있겠지만 프로그래밍에선 협업이 중요하다!
다른 사람이 내 코드를 봤을때 이 코드가 무엇인지 확실히 알아야 되는데 저 생성자 코드만 보고
캐릭터를 만들 때 무슨 속성을 설정할지 단번에 파악할 수 있을까?
- Builder 패턴을 적용할경우
Character warrior = new CharacterBuilder()
.SetName("전사")
.SetType("근접")
.SetHealth(100)
.SetDefense(50)
.SetSpeed(20)
.SetMana(150)
.Build();
이 방법은 속성의 순서를 기억할 필요가 없고, 해당 속성이 무엇인지 명확해 보인다!
- Builder란 무엇인가?
복잡한 인스턴스를 조립하는 방식!
객체를 생성하는 방법(How)과 객체를 구현하는 방법(What)을 분리하여,
동일한 생성 절차에서 다양한 표현 결과를 만들 수 있도록 하는 패턴이다.
복잡한 객체를 생성과 구현을 분리해서 관리해주는 느낌으로 생각하면 된다!
- Builder 패턴을 사용해보자! (c#)
1. 먼저 캐릭터 클래스를 설계한다!
캐릭터는 이름, 직업, 무기, 체력, 마나, 속도 속성이 있다!
public class PlayerCharacter
{
public string Name { get; set; }
public string Job { get; set; }
public string Weapon { get; set; }
public int Health { get; set; }
public int Mana { get; set; }
public int Speed { get; set; }
public void PlayerShow()
{
Console.WriteLine($"[캐릭터 생성 완료] 이름: {Name}, 직업: {Job}, 무기: {Weapon}, " +
$"체력: {Health}, 마나: {Mana}, 속도: {Speed}");
}
}
2. 빌더 인터페이스를 정의한다.
// 빌더 인터페이스
public interface ICharaBuilder
{
ICharaBuilder SetName(string name);
ICharaBuilder SetJob(string job);
ICharaBuilder SetWeapon(string weapon);
ICharaBuilder SetHealth(int health);
ICharaBuilder SetMana(int mana);
PlayerCharacter Build();
}
3. 생성하는 방법(How)을 정의한다!
// 빌더 구현 방법
public class CharacterBuilder : ICharaBuilder
{
private PlayerCharacter player = new PlayerCharacter();
public ICharaBuilder SetName(string name)
{
player.Name = name;
return this;
}
public ICharaBuilder SetJob(string job)
{
player.Job = job;
return this;
}
public ICharaBuilder SetWeapon(string weapon)
{
player.Weapon = weapon;
return this;
}
public ICharaBuilder SetHealth(int health)
{
player.Health = health;
return this;
}
public ICharaBuilder SetMana(int mana)
{
player.Mana = mana;
return this;
}
public PlayerCharacter Build()
{
return player;
}
}
생성하는 방법 설계가 끝났다면 이제 구현할 준비가 다 끝났다는 소리다!
마지막으로 Main에서 구현해서 실행시켜보자!
3. Main에서 구현(What)한다!
internal class Program
{
static void Main(string[] args)
{
PlayerCharacter player = new CharacterBuilder()
.SetName("전사")
.SetJob("Warrior")
.SetWeapon("대검")
.SetHealth(150)
.SetMana(50)
.Build();
player.PlayerShow();
}
}
- 어? 속도 (Speed) 속성을 추가해야해요!
추후 게임이 개발되거나 운영할 때 새로운 속성이 필요하는 경우가 발생할 수 있다!
새롭게 추가될 때 기존에 작성했던 코드들을 다 바꿔줘야 하는가? 이러면 너무 힘들다....ㅠㅠ
이 부분이 Builder 패턴이 유지보수가 용이하다는 점이다!
Speed 관련된 속성과 메서드만 추가하고 기존에 미리 만들었던 메서드들은 일절 건들지 않기 때문이다! (OCP 법칙)
ICharaBuilder SetSpeed(int speed);
먼저 빌더 인터페이스 부분에 Speed를 추가하고
public ICharaBuilder SetSpeed(int speed)
{
player.Speed = speed;
return this;
}
그 다음 빌더 코드에서 속도 코드를 새로 추가한다!
마지막으로 Main에서 캐릭터를 생성할 때 속도만 추가하면
이렇게 기존 코드는 건들지 않으면서 속도 속성만 추가된 것을 확인 할 수 있다!
- 최종 정리
코드 | 설명 | |
객체를 생성하는 방법 | CharacterBuilder 클래스 | 객체를 어떻게 생성할지(How)를 정의한다! |
객체를 구현하는 방법 | new CharacterBuilder().SetName()... 부분 | 빌더를 사용해서 실제 객체를 구현한다! |