Singleton Pattern, Adapter Pattern

sejun-Lee·2025년 4월 21일

UnityEngine

목록 보기
7/12

디자인 패턴 Singleton

<싱글톤 패턴>

  • 오직 한 개의 클래스 인스턴스만을 갖도록 보장
  • 이에 대한 전역적인 접근점을 제공

<구현>

  1. 단일 인스턴스를 유지하기 위해 생성자의 접근권한을 외부에서 생성할 수 없도록 제한
  2. 단일 인스턴스를 보관할 정적 변수를 구성
  3. 외부에서 접근이 가능한 GetInstance 함수를 구성
  4. GetInstance 함수에서 단일 인스턴스가 없을 경우 인스턴스를 생성하여 정적 변수에 참조
  5. GetInstance 함수에서 단일 인스턴스가 있을 경우 정적 변수에 참조된 인스턴스를 반환

<장점>

  1. 하나뿐인 존재로 주요 클래스 & 관리자 역할에 적합함
  2. 전역적 접근으로 참조에 필요한 작업이 없이 빠른 접근이 가능함
  3. 인스턴스들이 싱글톤을 통하여 데이터를 공유하기 쉬워짐

<주의점>

  1. 싱글톤은 너무 많은 책임을 짊어지는 경우가 많으며 단일책임원칙을 위반
  2. 싱글톤은 전역접근으로 코드의 결합도를 높이므로 남발하지 않아야함
  3. 싱글톤은 단위 테스트를 하기 어렵게 함
public class Singleton : MonoBehaviour
{
    private static Singleton instance; 

    public static Singleton GetInstance()   // 반드시 하나만 있음.
    {
        if (instance == null)
        {
            instance = new Singleton(); // 처음만 만들어 주고 
        }
        return instance;    // 다음부턴 만들어 진 것을 가져다 씀.
    }

    private Singleton() { }
}

디자인 패턴 Adapter Pattern

public class DamageAdapter : MonoBehaviour, IDamagable
{
    public UnityEvent<GameObject, int> OnDamaged;

    // Switch 가 직접 데미지를 받지 않고 현제 어뎁터를 통해서 Switch를 이벤트를 통해 SwitchAction 을 연결시켜서 스위치 기능 활성화
    public void TakeDamage(GameObject dealer, int damage)
    {
        OnDamaged?.Invoke(dealer, damage);
    }
}
 public interface IDamagable
{
    public GameObject gameObject {  get; }
    public void TakeDamage(GameObject dealer, int damage);
} 
public class Monster : MonoBehaviour, IDamagable
{
    [Header("Component")]
    [SerializeField] Transform eyeTransform;

    [Header("Property")]
    [SerializeField] float sightRange;
    [SerializeField] float moveSpeed;
    [SerializeField] int hp;
    public int HP {  get { return hp; } private set { hp = value; } }

    [SerializeField] GameObject target;

    private void Update()
    {
        DetectTarget(); // Physics로 타겟확인

        if (target != null) // target 이 있으면
        {
            Trace();    // 쫒아가라
        }
    }

    private void DetectTarget() // Player를 찾아라
    {
        if (Physics.Raycast(eyeTransform.position, eyeTransform.forward, out RaycastHit hitInfo, sightRange))
        {
            Debug.DrawLine(eyeTransform.position, hitInfo.point, Color.green);
            if (hitInfo.collider.gameObject.tag == "Player")    //DrawLine으로 player접촉시 타겟 확인
            {
                target = hitInfo.collider.gameObject;
            }
            else
            {
                target = null;
            }
            //TankController tank = hitInfo.collider.gameObject.GetComponent<TankController>();
            //if (tank != null)
            //{
            //    // 부딪쳤을때 탱크야? 그럼 데미지줘.
            //}
        }
        else
        {
            Debug.DrawLine(eyeTransform.position, eyeTransform.position + eyeTransform.forward * sightRange, Color.red);
            target = null;
        }

    }

    private void Trace()    // 쫒아가는 함수
    {
        transform.position = Vector3.MoveTowards(transform.position, target.transform.position, moveSpeed * Time.deltaTime);
        transform.LookAt(target.transform.position);
    }

    public void TakeDamage(GameObject dealer, int damage)
    {
        // TODO : 
        Debug.Log($"{gameObject.name} 이/가 {dealer.name}에게 피해를 {damage} 받았습니다.");
        HP -= damage;
        if (HP <= 0)    // 몬스터 hp가 0이 되면
        {
            Die();  // 몬스터 오브젝트 삭제
        }
    }

    private void Die()
    {
        GameManager.Instance.score += 10;   // 몬스터 제거시 10점
        Destroy(gameObject);    // 몬스터 제거
    }


}  
profile
초보 개발자

0개의 댓글