반응형
SMALL
GitHub - Romanticism-GameDeveloper/GameDeveloper-Client-Interview: 게임 클라이언트 개발자 면접 리스트 정리입
게임 클라이언트 개발자 면접 리스트 정리입니다. Contribute to Romanticism-GameDeveloper/GameDeveloper-Client-Interview development by creating an account on GitHub.
github.com
- 정의
- 클래스의 인스턴스를 한개만 가지게 하는 디자인 패턴
- 싱글톤 패턴의 사용이유 및 장점
- 싱글톤 패턴을 활용한 클래스의 경우 생명주기가 프로그램의 생명주기와 같게 된다.
이는 즉 프로그램이 메모리에 올라감과 동시에 함께 올라가며 프로그램이 종료될때 사라진다. - 메모리에 한번만 올라간다는 특징 덕에 여러 인스턴스의 생성을 통한 메모리 사용을 막을수 있다는 장점이 있다.
- 전역적으로 메모리에 올라가기 떄문에 다른 인스턴스들에서도 자유롭게 접근이 가능하다는 장점이 있다.
- 싱글톤 패턴을 활용한 클래스의 경우 생명주기가 프로그램의 생명주기와 같게 된다.
- 싱글톤 패턴의 단점
- static 클래스 이므로 메모리에 상시 올라가 있기 때문에 사용중이 아닐때도 메모리를 점유한다는 단점이 있다.
- 가장 큰 문제점은 동시성, 멀티스레드 환경에서 인스턴스가 2개 생기는 경우도 있고 여러 스레드에서 참조할때 동기화 처리를 해줘야 하는 번거로움이 있기에 디버깅이 어려워 질수 있다.
- 객체지향 프로그래밍과는 거리가 조금는 패턴, 의존도가 높아지기 때문에 싱글톤을 사용하는 객체들은 싱글톤 인스턴스에 종속되어야 하며 코드의 복잡성을 증가시킨다.
(객체들간의 결합도가 높아지면 유지보수가 힘들어 질수 있음)
- 프로젝트에서의 사용처
- Infomanager Class
- DataManager Class
- SoundManager Class(Mono)
- AtlasManager Class(Mono)
- EventDispatcher Class
실제 프로젝트 사용 예시 코드 (플레이어의 상태를 저장하는 Infomanager Class)
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
[Serializable]
public partial class InfoManager
{
public enum ePermanent
{
NO, YES
}
public enum eNextStageType
{
NONE = 1,
STAGE2,
STAGE3,
STAGE4,
}
public enum eTutorialType
{
NONE = -1,
SHOP,
STAT,
RESULT,
KNIGHTDIPOSIT,
ROGUEDIPOSIT,
DICE,
}
public static readonly InfoManager instance = new InfoManager();
private InfoManager() { }
public DungeonInfo dungeonInfo = new DungeonInfo();
public InventoryInfo inventoryInfo = new InventoryInfo();
public GameInfo gameInfo = new GameInfo();
/// <summary>
/// 인벤토리 정보 초기화 + 자동 저장( 던전씬 엔드시 반드시 호출 )
/// </summary>
public void InitInventoryInfo()
{
Debug.Log("<color=red>인벤토리 인포 이니셜라이징</color>");
this.inventoryInfo.isEquipment = false;
this.inventoryInfo.currentEquipmentsArr = null;
this.SaveInventoryInfo();
}
/// <summary>
/// 현재 유저 난이도 및 스테이지 정보 초기화( 던전씬 엔드시 반드시 호출 )
/// </summary>
public void InitDungeonInfo()
{
this.dungeonInfo.currentStepInfo = 1;
}
/// <summary>
/// 인벤토리 갯수 영구증가(1개) + 자동 저장
/// </summary>
public int IncreaseInventoryCount()
{
this.inventoryInfo.InventoryCount += 1;
this.SaveInventoryInfo();
return this.inventoryInfo.InventoryCount;
}
/// <summary>
/// 아이템 구매시 Inventory Info 에 구매아이템을 포함한 리스트 저장 + 자동 저장
/// </summary>
public void UpdateEquipmentInfo(List<string> EquipmentList)
{
Debug.Log("<color=red>인벤토리 인포 업데이트</color>");
if(EquipmentList.Count != 0)
this.inventoryInfo.isEquipment = true;
else
this.inventoryInfo.isEquipment = false;
this.inventoryInfo.currentEquipmentsArr = EquipmentList.ToArray();
this.SaveInventoryInfo();
}
/// <summary>
/// 플레이어 InventoryInfo 불러오기
/// </summary>
public void LoadInventoryInfo()
{
//string path = string.Format("{0}/Inventory_Info.json",
// Application.persistentDataPath);
//string json = File.ReadAllText(path);
//this.inventoryInfo = JsonConvert.DeserializeObject<InventoryInfo>(json);
//Debug.Log("인벤토리 인포 로드 완료");
//string path = string.Format("{0}/Inventory_Info.json", Application.persistentDataPath);
//string encryptedJson = File.ReadAllText(path);
//string decryptedJson = encryption.GetGeneric<string>(path, encryptedJson);
//this.inventoryInfo = JsonConvert.DeserializeObject<InventoryInfo>(decryptedJson);
//Debug.Log("<color=red>inventoryInfo loaded successfully.</color>");
try
{
string path = string.Format("{0}/Inventory_Info.json", Application.persistentDataPath);
string encryptedJson = File.ReadAllText(path);
string decryptedJson = encryption.GetGeneric<string>(path, encryptedJson);
//string json = File.ReadAllText(decryptedJson);
this.inventoryInfo = JsonConvert.DeserializeObject<InventoryInfo>(decryptedJson);
Debug.Log("<color=red>inventoryInfo loaded successfully.</color>");
}
catch (Exception e)
{
Debug.LogError("Failed to load inventoryInfo: " + e.Message);
}
}
/// <summary>
/// 플레이어 Inventory 저장
/// </summary>
public void SaveInventoryInfo()
{
//string path = string.Format("{0}/Inventory_Info.json",
// Application.persistentDataPath);
//string json = JsonConvert.SerializeObject(this.inventoryInfo);
//File.WriteAllText(path, json);
//Debug.Log("인벤토리 인포 저장 완료");
//string path = string.Format("{0}/Inventory_Info.json", Application.persistentDataPath);
//string json = JsonConvert.SerializeObject(this.inventoryInfo);
//encryption.SetGeneric(path, json);
//Debug.Log("<color=red>inventoryInfo saved successfully.</color>");
try
{
string path = string.Format("{0}/Inventory_Info.json", Application.persistentDataPath);
string json = JsonConvert.SerializeObject(this.inventoryInfo);
encryption.SetGeneric(path, json);
File.WriteAllText(path, json);
Debug.Log("<color=red>inventoryInfo saved successfully.</color>");
}
catch (Exception e)
{
Debug.LogError("Failed to save inventoryInfo: " + e.Message);
}
}
/// <summary>
/// 유저 난이도 변경 (스테이지 정보 입력시 해당 스테이지 시작 난이도로 자동 설정), 매개변수 없을시 = 난이도 + 1
/// <para>스테이지2 : 시작 난이도 = 3</para>
/// <para>스테이지3 : 시작 난이도 = 6</para>
/// <para>스테이지4 : 시작 난이도 = 10</para>
/// </summary>
/// <param name="stage">유저 난이도 점프시 스테이지 enum 입력</param>
public void ChangeDungeonStepInfo(eNextStageType stage = default(eNextStageType))
{
if (stage == default(eNextStageType))
{
if (this.dungeonInfo.currentStepInfo == 2)
this.dungeonInfo.currentStepInfo = 2;
else if (this.dungeonInfo.currentStepInfo == 5)
this.dungeonInfo.currentStepInfo = 5;
else if (this.dungeonInfo.currentStepInfo == 9)
this.dungeonInfo.currentStepInfo = 9;
else
this.dungeonInfo.currentStepInfo += 1;
}
else if (stage == eNextStageType.STAGE2)
{
this.dungeonInfo.currentStepInfo = 3;
}
else if (stage == eNextStageType.STAGE3)
{
this.dungeonInfo.currentStepInfo = 6;
}
else if (stage == eNextStageType.STAGE4)
{
this.dungeonInfo.currentStepInfo = 10;
}
}
public void LoadGameInfo()
{
//string path = string.Format("{0}/game_info.json",
// Application.persistentDataPath);
//string json = File.ReadAllText(path);
//this.gameInfo = JsonConvert.DeserializeObject<GameInfo>(json);
//Debug.Log("게임 인포 로드 완료");
//string path = string.Format("{0}/game_info.json", Application.persistentDataPath);
//string encryptedJson = File.ReadAllText(path);
//string decryptedJson = encryption.GetGeneric<string>(path, encryptedJson);
//this.gameInfo = JsonConvert.DeserializeObject<GameInfo>(decryptedJson);
//Debug.Log("<color=red>gameInfo loaded successfully.</color>");
try
{
string path = string.Format("{0}/game_info.json", Application.persistentDataPath);
string encryptedJson = File.ReadAllText(path);
string decryptedJson = encryption.GetGeneric<string>(path, encryptedJson);
//string json = File.ReadAllText(decryptedJson);
this.gameInfo = JsonConvert.DeserializeObject<GameInfo>(decryptedJson);
Debug.Log("<color=red>gameInfo loaded successfully.</color>");
}
catch (Exception e)
{
Debug.LogError("Failed to save inventoryInfo: " + e.Message);
}
}
/// <summary>
/// 플레이어 Inventory 저장
/// </summary>
public void SaveGameInfo()
{
//string path = string.Format("{0}/game_info.json",
// Application.persistentDataPath);
//string json = JsonConvert.SerializeObject(this.gameInfo);
//File.WriteAllText(path, json);
//Debug.Log("게임 인포 저장 완료");
//string path = string.Format("{0}/game_info.json", Application.persistentDataPath);
//string json = JsonConvert.SerializeObject(this.gameInfo);
//encryption.SetGeneric(path, json);
//Debug.Log("<color=red>gameInfo saved successfully.</color>");
try
{
string path = string.Format("{0}/game_info.json", Application.persistentDataPath);
string json = JsonConvert.SerializeObject(this.gameInfo);
encryption.SetGeneric(path, json);
File.WriteAllText(path, json);
Debug.Log("<color=red>gameInfo saved successfully.</color>");
}
catch (Exception e)
{
Debug.LogError("Failed to save gameInfo: " + e.Message);
}
}
/// <summary>
/// 튜토리얼 완료여부 저장 + 자동저장
/// </summary>
/// <param name="type"></param>
public void TutorialDone(eTutorialType type)
{
switch (type)
{
case eTutorialType.SHOP:
this.gameInfo.isShopTuto = true;
break;
case eTutorialType.STAT:
this.gameInfo.isStatTuto = true;
break;
case eTutorialType.RESULT:
this.gameInfo.isResultTuto = true;
break;
case eTutorialType.KNIGHTDIPOSIT:
this.gameInfo.isKnightDipositTuto = true;
break;
case eTutorialType.ROGUEDIPOSIT:
this.gameInfo.isRogueDipositTuto = true;
break;
case eTutorialType.DICE:
this.gameInfo.isDiceTuto = true;
break;
}
this.SaveGameInfo();
}
}
반응형
LIST
'디자인 패턴 정리 > 개인공부' 카테고리의 다른 글
옵저버 패턴 (1) | 2023.07.13 |
---|---|
팩토리 패턴 (0) | 2023.07.13 |
옵저버 패턴을 적용한 EventDispatcher 클래스 (0) | 2023.06.12 |