디자인패턴

반복자패턴

khkg12 2023. 11. 23. 15:34

반복자패턴이란?

일련의 데이터 집합에서 순차적인 접근을 제공해주는 패턴이다. IEnumerator를 상속받은 순서에 대한 클래스를 만들어주고 그 순서로 컬렉션을 반복할 수 있게 해주는 것이다. 예시로 카드덱 클래스가 있을 때 카드덱에 대한 순서의 의미를 가진 클래스를 구현하고, 그 순서를 받아 커스텀한 순차대로 카드를 출력하는 것이다. 

 

예시코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class Card
{
    public string name;
    public int cost;
    public Card(string name, int cost)
    {
        this.name = name;
        this.cost = cost;
    }
}
public class Deck : List<Card>
{
    public class DeckEnumerator : IEnumerator // 클래스 내부의 컬렉션에 대해 반복할 수 있도록 해주는 인터페이스, 이를 상속받아 커스텀
    {
        List<Card> cards;
        public event Action onEmpty;
        int curIndex = -1;
        public DeckEnumerator(Deck deck)
        {
            cards = deck;
        }
        public object Current => cards[curIndex];

        public bool MoveNext()
        {
            curIndex++;
            bool isEmpty = curIndex >= cards.Count;
            if (isEmpty)
                onEmpty?.Invoke(); // 비어있을 때! 호출되는 이벤트
            return !isEmpty;
        }

        public void Reset()
        {
            curIndex = -1;
        }
    }

    public new DeckEnumerator GetEnumerator() // 컬렉션의 반복자를 리턴하는 함수
    {
        return new DeckEnumerator(this);
    }

}

public class DeckController : MonoBehaviour
{
    Deck deck;
    public int hp = 30;
    public int reduceHp = 1;
    Deck.DeckEnumerator deckEnumerator;
    void Start()
    {
        deck = new Deck();
        deck.Add(new Card("강타", 3));
        deck.Add(new Card("이글거리는도끼", 2));
        deck.Add(new Card("방패올리기", 3));

        deckEnumerator = deck.GetEnumerator(); // 반복자 저장
        deckEnumerator.onEmpty += () => {
            Debug.Log("카드가 다 떨어졌습니다.");
            hp -= reduceHp++;
        };
    }

    void Draw()
    {
        if (deckEnumerator.MoveNext()) 
        {
            Card drawCard = (Card)deckEnumerator.Current;
            Debug.Log(drawCard.name);
        }
    }
    
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Draw();
        }
    }
}