Chapter 10. 빌더 패턴(Builder Pattern)
카테고리: Design Pattern
인프런에 있는 이재환님의 강의 게임 디자인 패턴 with Unity 를 듣고 정리한 필기입니다. 😀
Chapter 10. Builder Pattern
🔔 개념
객체를 생성할 때, 그 객체를 구성하는 부분 부분을 단계별로 먼저 생성하고 이를 조합함으로써 객체 전체를 생성한다.
- 복잡합 유형의 오브젝트를 작성할 때 도움된다.
- 생성할 객체의 종류를 손쉽게 추가, 확장이 가능한 설계.
- 플레이어 캐릭터 별개의 옷, 무기 등등을 조합하고 장착하는 등등 여러가지 경우에 상요될 수 있다.
빌더 패턴 Vs. 추상 팩토리 패턴
- Builder
- 복잡한 객체의 단계별 생성에 중점을 두고 있는 패턴
- 마지막 단계에서 생성한 제품을 리턴한다.
- Abstract Factory
- 제품의 유사군들이 존재하는 경우 유연한 설계에 중점을 두는 패턴
- (단계마다) 만드는 즉시 제품을 리턴한다.
- 테란, 프로토스 공장을 만들어둔 후 만드는 즉시 리턴
🔔 예제 1
- 탈 것
Vehicle
- 바퀴가 2 개인 것 👉 Motocycle
- 바퀴가 4 개인 것 👉 Car
- 인터페이스
IVehicleBuilder
- 상속
CarBuilder
- 상속
MotorCycleBuilder
- 상속
📜Vehicle.cs
- AddPart 함수
- 부품을 모아서 붙임
- GetPartsList 함수
- 부품 리스트를 리턴
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Our final product
class Vehicle
{
public VehicleType vehicleType;
private List<string> _parts = new List<string>();
// Constructor method
public Vehicle(VehicleType vehicleType)
{
this.vehicleType = vehicleType;
}
public void AddPart(string desc)
{
_parts.Add(desc);
}
public string GetPartsList()
{
string partsList = vehicleType.ToString() + " parts:\n\t";
foreach (string part in _parts)
{
partsList += part + " ";
}
return partsList;
}
}
📜InterfaceBuilder.cs
인터페이스
- 탈 것의 인터페이스
- 프레임 만들기
- 엔진 만들기
- 바퀴 만들기
using UnityEngine;
using System.Collections.Generic;
// 'abstract Builder' class
interface IVehicleBuilder
{
Vehicle getVehicle();
void BuildFrame(); // 프레임 만들기
void BuildEngine(); // 엔진 만들기
void BuildWheels(); // 바퀴 만들기
}
public enum VehicleType
{
Car,
MotorCycle
}
📜CarBuilder.cs
using UnityEngine;
class CarBuilder : IVehicleBuilder
{
private Vehicle _vehicle;
public Vehicle getVehicle()
{
return _vehicle;
}
public CarBuilder()
{
// 빌더가 만들어질 때 아무것도 없는 차도 하나 만든다. (부품이 붙기 전)
_vehicle = new Vehicle(VehicleType.Car);
}
public void BuildFrame() // Car의 프레임 만들기
{
_vehicle.AddPart("강철");
}
public void BuildEngine() // Car의 엔진 만들기
{
_vehicle.AddPart("100마력");
}
public void BuildWheels() // Car의 바퀴 만들기
{
_vehicle.AddPart("앞.왼쪽 바퀴");
_vehicle.AddPart("앞.오른쪽 바퀴");
_vehicle.AddPart("뒤.왼쪽 바퀴");
_vehicle.AddPart("뒤.오른쪽 바퀴");
}
}
📜MotorCycleBuilder.cs
using UnityEngine;
class MotorCycleBuilder : IVehicleBuilder
{
private Vehicle _vehicle;
public Vehicle getVehicle()
{
return _vehicle;
}
public MotorCycleBuilder()
{
// 빌더가 만들어질 때 아무것도 없는 모터싸이클도 하나 만든다.(부품이 붙기 전)
_vehicle = new Vehicle(VehicleType.MotorCycle);
}
public void BuildFrame() // MotorCycle의 프레임 만들기
{
_vehicle.AddPart("알루미늄");
}
public void BuildEngine() // MotorCycle의 엔진 만들기
{
_vehicle.AddPart("50마력");
}
public void BuildWheels() // MotorCycle의 바퀴 만들기
{
_vehicle.AddPart("앞 바퀴");
_vehicle.AddPart("뒤 바퀴");
}
}
📜Engineer.cs
부품들(프레임, 엔진, 바퀴)를 만들어주는 역할
다형성
- IVehicleBuilder vehicleBuilder
- 어떤 종류의 탈 것이 들어오느냐에 따라서 부품들이 다르게 생성되겠지
- IVehicleBuilder vehicleBuilder
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class Engineer
{
public void Construct(IVehicleBuilder vehicleBuilder)
{
vehicleBuilder.BuildFrame();
vehicleBuilder.BuildEngine();
vehicleBuilder.BuildWheels();
}
}
📜BuilderUse.cs
using UnityEngine;
public class BuilderUse : MonoBehaviour
{
void Start()
{
// Instantiate the director and builders
Engineer engineer = new Engineer(); // ⭐ 엔지니어 만들기
CarBuilder carBuilder = new CarBuilder(); // 빈 Car 만들기
MotorCycleBuilder motorCycleBuilder = new MotorCycleBuilder(); // 빈 MotorCycle 만들기
// 빌더를 통해 구성해야 할 제품을 입력받아 제품을 구성한다.
// 부품들을 붙인다.
engineer.Construct(carBuilder);
engineer.Construct(motorCycleBuilder);
// 최종 생산된 완성된 제품을 반환받는다.
Vehicle car = carBuilder.getVehicle();
Debug.Log(car.GetPartsList());
Vehicle motorCycle = motorCycleBuilder.getVehicle();
Debug.Log(motorCycle.GetPartsList());
}
}
🔔 예제 2
- 탈 것
Vehicle
- 바퀴가 2 개인 것 👉 Motocycle
- 바퀴가 4 개인 것 👉 Car
- 인터페이스
IVehicleBuilder
- 상속
CarBuilder
- 상속
MotorCycleBuilder
- 상속
- 프리팹
- 🟦Engine
- 노란 구
- 🟦FrameCar
- 파란 큐브
- 🟦FrameCycle
- 초록 큐브
- 🟦ParentOfVehicle
- 빈 오브젝트로 부품들을 모으기 위한 용도
- 게임이 실행되면 부품들이 얘의 자식이되어 자동차, 오토바이를 만든다.
- 🟦Wheel
- 빨간 구
- 🟦Engine
📜Vehicle.cs
🟦ParentOfVehicle 프리팹에 붙인다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Our final product
public class Vehicle : MonoBehaviour
{
private VehicleType vehicleType;
public void setVehicleType(VehicleType vehicleType)
{
this.vehicleType = vehicleType;
}
public void AddPart(GameObject part, Vector3 localPosition)
{
GameObject obj = Instantiate(part) as GameObject;
obj.transform.localPosition = localPosition;
obj.transform.SetParent(this.transform);
}
public string GetPartsList()
{
string partsList = vehicleType.ToString() + " parts:\n\t";
Transform[] trs = GetComponentsInChildren<Transform>();
for (int i = 1; i < trs.Length; i++)
{
partsList += trs[i].gameObject.name + " ";
}
return partsList;
}
}
- 유니티에서 사용하는 것이니 MonoBehaviour를 상속 받고
new
가 아닌Instantiate
로 생성
📜InterfaceBuilder.cs
using UnityEngine;
using System.Collections.Generic;
// 'abstract Builder' class
interface IVehicleBuilder
{
Vehicle getVehicle();
void BuildFrame();
void BuildEngine();
void BuildWheels();
}
public enum VehicleType
{
Car,
MotorCycle
}
- 예제 1과 똑같
📜CarBuilder.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class CarBuilder : MonoBehaviour, IVehicleBuilder
{
public GameObject ParentOfVehicle;
public GameObject frame;
public GameObject engine;
public GameObject wheel1;
public GameObject wheel2;
public GameObject wheel3;
public GameObject wheel4;
private Vehicle _vehicle;
public Vehicle getVehicle()
{
return _vehicle;
}
public void makeVehicle()
{
//_vehicle = new Vehicle(VehicleType.Car);
GameObject obj = Instantiate(ParentOfVehicle) as GameObject;
_vehicle = obj.GetComponent<Vehicle>();
_vehicle.setVehicleType(VehicleType.Car);
}
public void BuildFrame()
{
_vehicle.AddPart(frame, Vector3.zero);
}
public void BuildEngine()
{
_vehicle.AddPart(engine, new Vector3(0, 0.5f, 0));
}
public void BuildWheels()
{
_vehicle.AddPart(wheel1, new Vector3(0.75f, -0.5f, 0.5f));
_vehicle.AddPart(wheel2, new Vector3(-0.75f, -0.5f, 0.5f));
_vehicle.AddPart(wheel3, new Vector3(-0.75f, -0.5f, -0.5f));
_vehicle.AddPart(wheel4, new Vector3(0.75f, -0.5f, -0.5f));
}
}
📜MotorCycleBuilder.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class MotorCycleBuilder : MonoBehaviour, IVehicleBuilder
{
public GameObject ParentOfVehicle;
public GameObject frame;
public GameObject engine;
public GameObject wheel1;
public GameObject wheel2;
private Vehicle _vehicle;
public Vehicle getVehicle()
{
return _vehicle;
}
public void makeVehicle()
{
//_vehicle = new Vehicle(VehicleType.MotorCycle);
GameObject obj = Instantiate(ParentOfVehicle) as GameObject;
_vehicle = obj.GetComponent<Vehicle>();
_vehicle.setVehicleType(VehicleType.MotorCycle);
}
public void BuildFrame()
{
_vehicle.AddPart(frame, Vector3.zero);
}
public void BuildEngine()
{
_vehicle.AddPart(engine, new Vector3(0, 0.5f, 0));
}
public void BuildWheels()
{
_vehicle.AddPart(wheel1, new Vector3(1.5f, 0, 0));
_vehicle.AddPart(wheel2, new Vector3(-1.5f, 0, 0));
}
}
📜Engineer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Our 'Director' class.
class Engineer
{
public void Construct(IVehicleBuilder vehicleBuilder)
{
vehicleBuilder.BuildFrame();
vehicleBuilder.BuildEngine();
vehicleBuilder.BuildWheels();
}
}
📜BuilderUse.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BuilderUse : MonoBehaviour
{
void Start()
{
// Instantiate the director and builders
Engineer engineer = new Engineer();
//CarBuilder carBuilder = new CarBuilder();
CarBuilder carBuilder = GetComponent<CarBuilder>();
carBuilder.makeVehicle();
//MotorCycleBuilder motorCycleBuilder = new MotorCycleBuilder();
MotorCycleBuilder motorCycleBuilder = GetComponent<MotorCycleBuilder>();
motorCycleBuilder.makeVehicle();
// 빌더를 통해 구성해야 할 제품을 입력받아 제품을 구성한다.
engineer.Construct(carBuilder);
engineer.Construct(motorCycleBuilder);
// 최종 생산된 제품을 반환받는다.
Vehicle car = carBuilder.getVehicle();
Debug.Log(car.GetPartsList());
Vehicle motorCycle = motorCycleBuilder.getVehicle();
Debug.Log(motorCycle.GetPartsList());
// 최종 생산된 제품의 위치를 지정한다.
car.transform.position = new Vector3(-3f, 0, 0);
motorCycle.transform.position = new Vector3(3f, 0, 0);
}
}
유니티 적용
Game Manager
라는 빈 오브젝트를 만든 후- 📜CarBuilder.cs 와 📜MotorCycleBuilder.cs 와 📜BuilderUse.cs 를 붙여준다.
- 프리팹 연결
- 아래와 같이 만들어진 것을 볼 수 있다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글남기기