내일배움캠프 39일차 TIL, 디자인패턴(빌더, 추상팩토리)

황오영·2024년 6월 12일
0

TIL

목록 보기
39/56
post-thumbnail

빌더패턴

<출처 : 챌린지반 강의노트>
<출처 : https://refactoring.guru/ko/design-patterns/builder>
<출처 : https://refactoring.guru/ko/design-patterns/abstract-factory>

빌더 패턴?

  • 로봇이나 집과 같은 복잡한 객체를 생성하는 것은 매우 어렵다. 이러한 객체 생성을 효과적으로 만드는 것이 빌더 패턴
  • 복잡한 객체를 순차적으로 같은 제작 코드를 사용하여 객체의 다양한 유형과 표현을 제작할 수 있다.
  • 마지 구형의 점토에서 직육면체로 만들고 > 팔을 붙이고 > 얼굴과 다리를 붙이는 생성과정으로 가는것 이러한 객체 생성 과정을 체계화하는 것이다.
  • 빌더 패턴에는 빌더 클래스가 등장한다.

코드 예시

public class Character
{
    public string Name { get; set; }
    public int Health { get; set; }
    public int Strength { get; set; }
    public int Agility { get; set; }

    public void DisplayCharacterInfo()
    {
        Debug.Log($"Name: {Name}, Health: {Health}, Strength: {Strength}, Agility: {Agility}");
    }
}

public class CharacterBuilder
{
    private Character character;

		// 생성자부터 컨베이어벨트에 탄다고 생각하면 편함
    public CharacterBuilder()
    {
        character = new Character();
    }

	//이름을 만들어주기
    public CharacterBuilder SetName(string name)
    {
        character.Name = name;
        return this;
    }
	
    //체력을 설정하기
    public CharacterBuilder SetHealth(int health)
    {
        character.Health = health;
        return this;
    }

	//STR설정하기
    public CharacterBuilder SetStrength(int strength)
    {
        character.Strength = strength;
        return this;
    }
    
	//능력설정하기
    public CharacterBuilder SetAgility(int agility)
    {
        character.Agility = agility;
        return this;
    }

	//최종반환
    public Character Build()
    {
        return character;
    }
}

using UnityEngine;

public class Game : MonoBehaviour
{
    void Start()
    {
        CharacterBuilder builder = new CharacterBuilder();

        Character hero = builder.SetName("Hero")
                                .SetHealth(100)
                                .SetStrength(50)
                                .SetAgility(30)
                                .Build();

        Character villain = builder.SetName("Villain")
                                   .SetHealth(120)
                                   .SetStrength(70)
                                   .SetAgility(20)
                                   .Build();

        hero.DisplayCharacterInfo();
        villain.DisplayCharacterInfo();
    }
}
  • 이런식으로 빌더클래스를 두고 하나하나씩 조리햅주고 공정과정을 거치는것이 빌더 패턴이다.
public class CharacterDirector
{
    private CharacterBuilder builder;

    public CharacterDirector(CharacterBuilder builder)
    {
        this.builder = builder;
    }

    public Character ConstructWarrior()
    {
        return builder.SetName("Warrior")
                      .SetHealth(200)
                      .SetStrength(150)
                      .SetAgility(50)
                      .Build();
    }

    public Character ConstructMage()
    {
        return builder.SetName("Mage")
                      .SetHealth(100)
                      .SetStrength(50)
                      .SetAgility(100)
                      .Build();
    }
}

public class Game : MonoBehaviour
{
    void Start()
    {
        CharacterBuilder builder = new CharacterBuilder();
        CharacterDirector director = new CharacterDirector(builder);

        Character warrior = director.ConstructWarrior();
        warrior.DisplayCharacterInfo();

        Character mage = director.ConstructMage();
        mage.DisplayCharacterInfo();
    }
}
  • 위는 살짝의 변형으로 Director(감시자)가 있는 부분이라고 보면 좋다. 이부분은 선택사항으로 디렉터가 있게 된다면 순서와 설정에 따라 제품을 관리할 수 있게 된다!

장단점

  • 객체들을 단계별로 생성할 수 있다. 재귀적으로 절차 관리가 가능
  • 제품의 다양한 표현을 만들 때 생성코드를 재사용 할 수 있다.
  • 단일책임원칙을 잘지킨다.
  • 여러개의 클래스를 생성하다보니 복잡성은 증가한다.

팩토리 메서드 + 추상팩토리

팩토리 메서드

  • 부모 클래스에서 객체들을 생성할 수 있는 인터페이스를 제공하여 클라이언트 코드가 구체적인 클래스의 인스턴스를 생성하지 않고 패토리를 통해 생성하도록 한다.
  • 이러한 팩토리라는 공장에서 제품을이라는 객체를 반환하는 패턴이다.

추상 팩토리

  • 추상팩토리는 관련된 객체들의 구상 클래스를 지정하지 않고도 관련 객체들의 모음을 생성할수 있도록 하는패턴
  • 추상 공장 패턴은 우선 각 객체에 맞게 개별적인 인터페이스를 선언 하고 각 객체들이 인터페이스를 따르게 하는 규칙을 설정한뒤에 추상 팩토리 패턴을 선언하여 객체군 내의 모든 개별 객체들이 이러한 인터페이스를 가지게 하는것
public interface IEnemy
{
    void Attack();
}

public class Goblin : IEnemy
{
    public void Attack()
    {
        Debug.Log("Goblin attacks!");
    }
}

public class Orc : IEnemy
{
    public void Attack()
    {
        Debug.Log("Orc attacks!");
    }
}

public interface IWeapon
{
    void Use();
}

public class Sword : IWeapon
{
    public void Use()
    {
        Debug.Log("Swinging a sword!");
    }
}

public class Axe : IWeapon
{
    public void Use()
    {
        Debug.Log("Swinging an axe!");
    }
}

public interface IAbstractFactory
{
    IEnemy CreateEnemy();
    IWeapon CreateWeapon();
}

public class GoblinFactory : IAbstractFactory
{
    public IEnemy CreateEnemy()
    {
        return new Goblin();
    }

    public IWeapon CreateWeapon()
    {
        return new Sword();
    }
}

public class OrcFactory : IAbstractFactory
{
    public IEnemy CreateEnemy()
    {
        return new Orc();
    }

    public IWeapon CreateWeapon()
    {
        return new Axe();
    }
}

public class Battle
{
    private IEnemy enemy;
    private IWeapon weapon;

    public Battle(IAbstractFactory factory)
    {
        this.enemy = factory.CreateEnemy();
        this.weapon = factory.CreateWeapon();
    }

    public void Start()
    {
        enemy.Attack();
        weapon.Use();
    }
}

public class TestScript : MonoBehaviour
{
    void Start()
    {
        // Goblin factory
        IAbstractFactory goblinFactory = new GoblinFactory();
        Battle goblinBattle = new Battle(goblinFactory);
        goblinBattle.Start();

        // Orc factory
        IAbstractFactory orcFactory = new OrcFactory();
        Battle orcBattle = new Battle(orcFactory);
        orcBattle.Start();
    }
}
  • 위 예시처럼 인터페이스로 IEnemy를 선언하고 고블린과 오크가 이를 상속받는다 IWeapon을 만들고 Sword와 Axe가 이를 상속받는다.
  • 그러한 것들을 상송받은 인터페이스인 IAbstractFactory을 선언하고 각강에 공장에 투입시켜주면
    칼을든 고블린 칼을든 오크 도끼를든 고블린 도끼를든 오크를 만들수 있게 되는것!

장단점

  • 팩토리에서 생성되는 제품들의 상호 호환을 보장할 수 있음
  • 구상 제품들과 클라이언트 코드사이의 단단한 결합을 피할 수 있다.
  • 단일 책임 원칙 : 제품 생성 코드를 한 곳으로 추출하여 코드를 더 쉽게 유지보수할 수 있음
  • 개방/폐쇄 원칙, 기존 클라이언트 코드를 훼손하지 않고 제품의 새로운 변형을 생성할 수 있따.
  • 하지만 패턴과 함께 새로운인터페이스와 클래스들이 많이 도임되므로 코드가 더 복잡해 질 수 있다.

오늘의 회고

  • 오늘 심화주차강의 + 최종프로젝트 팀빌딩을 진행했는데 최종프로젝트는 고민이 좀 많다. 팀장을 해야할지 팀원을 해야할지부터 고민이고...
  • 제일 큰 고민은 '어떤 게임'을 만들고 싶은가에 대한 고민이다. 낭만을 챙겨야할지 이상을 챙겨할지의 사이에 많이 고민이 있다.
  • 이미 한번 짧은 게임잼 경험에 의해 의욕만 앞선다고 모든것이 해결되지 않고 지난 게임잼에서 역시 초반에 고생을 많이했다 보니 그 이상을 하고싶은데 아직 그러한 타협점을 잘 찾지못해 자신이 많이없다.
  • 이번주랑 해서 고민과 인디게임 레퍼런스들을 많이 찾아봐서 결심을 좀 해봐야 할 것같다.
  • 요즘 좋아하는 애니의 명대사 '너를 믿는 나를 믿어'라는 말처럼 나 자신을 믿고 잘 해봐야겠다!
  • 우선은 심화주차에 집중
profile
게임개발을 꿈꾸는 개발자

0개의 댓글