게임 시스템을 설계하기 위해선 유지보수성과 확장성이 좋은 코드를 작성하는 것이 중요합니다. 이를 위해 객체 지향 설계 원칙인 SOLID 원칙을 따르면 코드 구조를 더 명확하고 효율적으로 설계할 수 있습니다. 이번 포스트에서는 SOLID 원칙이 무엇인지, Unity Korea 채널을 통해 정리하고 관련 정보를 알아보겠습니다.
GoF & SOLID
GoF: "Gang of Four"의 약자로, 디자인 패턴에서 중요한 역할을 수행한 4명의 개발자를 의미합니다.
이들은 객체 지향 소프트웨어 설계를 체계화하여 디자인 패턴을 정리하였으며, 디자인 패턴은 크게 생성 패턴, 구조 패턴, 행동 패턴으로 나뉩니다. 총 23개의 패턴이 존재하는데, 추후에 게임 개발에서 자주 사용되는 패턴에 대해 따로 정리하도록 하겠습니다.
SOLID: 객체 지향 프로그래밍에서 코드 설계를 유연하게 만들고 유지보수가 용이하도록 만드는 5가지 원칙을 의미합니다.
이 원칙을 통해 게임 시스템의 유지보수와 확장성을 보장할 수 있습니다. Unity와 같은 게임 엔진에서도 이 원칙을 따르면 게임 시스템을 효율적으로 설계할 수 있으며, 콘텐츠를 쉽게 확장하고 개선할 수 있습니다.
단일 책임 원칙 (Single Responsibility Principle)
단일 책임 원칙(SRP): 클래스나 모듈이 오직 하나의 책임만 가지는 원칙
모든 객체는 하나의 책임만 가지며, 그 책임은 완전히 캡슐화가 이루이집니다. 그리고 객체가 제공하는 모든 기능은 이 책임에 부합해야 합니다. 이 원칙을 따르면 코드가 짧아져 가독성이 증가하며, 객체 간의 관계가 명확해져 확장성에 용이합니다. 또한, 모듈식 설계를 통해 재사용성이 좋습니다.
Unity Engine에서 Component (패턴)을 쉽게 확인할 수 있습니다. 이 Component는 하나의 책임에 대해 데이터를 관리하고 로직을 처리합니다. 이러한 구조를 통해 개발자는 Component를 조합하여 원하는 오브젝트를 쉽게 만들 수 있습니다.
개방 폐쇄 원칙 (Open-closed Principle)
개방 폐쇄 원칙(OCP): 클래스나 모듈은 확장에 대해서 열려 있고, 수정에 대해서는 닫혀 있는 원칙
새로운 기능이나 시스템이 추가될 때, 기존 시스템을 변경하지 않고 추가적인 코드나 모듈을 통해 기능을 확장할 수 있어야 합니다. 이를 통해 협업에서 시스템이 변경되더라도 다른 부분에 영향을 주지 않기 때문에 유지보수가 용이하고 확장성이 뛰어나게 됩니다.
Unity에서 게임을 개발하다 보면 상속 구조를 쉽게 확인할 수 있습니다. 위 예시처럼, Shape 클래스를 상속 받아 Rectangle, Circle를 코드 수정 없이 새로운 코드를 추가하여 쉽게 확장할 수 있습니다.
리스코프 치환 원칙 (Liskov substitution principle)
리스코프 치환 원칙(LSP): 고수준 모듈은 언제나 저수준 모듈로 대체될 수 있어야 한다는 원칙
상속 관계에서 부모 클래스의 인스턴스를 사용하는 곳에서 자식 클래스의 인스턴스를 대신 넣더라도 프로그램이 정상적으로 작동해야 함을 의미합니다. 이를 통해 상속 계층 구조의 일관성을 보장하고, 클래스 간의 의존성을 낮출 수 있습니다. 만약 부모 클래스의 어느 한 부분이라도 물려줄 수 없다면 그것은 리스코프 치환 원칙을 위반한 것입니다.
예를 들어, Train이 RoadVehicle을 상속받는다고 가정합니다. RoadVehicle은 ITurnable을 포함하지만, Train은 사실 ITurnable을 필요로 하지 않습니다. 즉, 리스코프 치환 원칙에 위배 됩니다. 따라서 RailVehicle 이라는 새로운 객체를 추가하여 이것을 상속받도록 합니다.
인터페이스 분리 원칙 (Interface Segregation principle)
인터페이스 분리 원칙(ISP): 인터페이스를 작고 구체적으로 분리하는 원칙
큰 인터페이스를 구현한다면 이후에 특정 기능을 사용하지 않는 경우가 발생할 수 있습니다. 따라서 인터페이스 기능을 구체적으로 정의하고, 작게 나누어 필요한 기능만 구현할 수 있도록 합니다. 이를 통해 내부 의존성을 약화시킬 수 있으며, 코드를 유연하게 설계할 수 있습니다.
예를 들어, 이동 기능, 피격 기능, 폭발 여부 등 구체적인 기능을 하나의 인터페이스로 구현합니다. 그리고 각 인터페이스를 조합하여 객체를 표현합니다. 이를 통해 게임 시스템을 유연하게 설계할 수 있으며, 유지보수를 강화할 수 있습니다.
의존 역전 원칙 (Dependency Inversion Principle)
의존 역전 원칙(DIP): 고수준 모듈과 저수준 모듈이 서로 의존하지 않도록 하며, 둘 다 추상화에 의존해야 한다는 원칙
고수준 모듈이 저수준 모듈에 의존하지 않도록 하여 모듈 간의 결합도를 낮춥니다. 이를 통해 시스템의 결합을 낮출 수 있고 코드를 더 유연하고 유지보수에 용이하도록 만듭니다.
예를 들어, Door 객체가 아닌, 상위 개념인 ISwitchable 인터페이스를 통해 기능을 구현하여 결합도를 낮춥니다. 이러면 추후에 열고 닫는 개념이 아닌, 전등을 끄고 키는 개념으로 확장시킬 수도 있습니다.
정리
SOLID 원칙에 기반하여 게임 시스템을 설계한다면 서비스를 원활하게 유지보수할 수 있으며, 새로운 기능이나 시스템을 쉽게 확장할 수 있습니다. 이러한 설계 원칙들을 인지하여 게임 시스템을 설계해보세요.
참고 자료
[디자인 패턴 관련 자료]
https://refactoring.guru/ko/design-patterns
[Unity Korea 채널]
'유니티(Unity) > 이론 정리' 카테고리의 다른 글
Unitask의 개념과 사용법 (0) | 2024.11.14 |
---|---|
코루틴(Coroutine)의 개념과 동작 원리 (4) | 2024.11.13 |
클래스 이름 짓기 [ 2편 ] + MVC 패턴 (2) | 2024.11.11 |
클래스 이름 짓기 [ 1편 ] (1) | 2024.11.10 |
에셋 번들(Asset Bundle) 이론 정리 (1) | 2024.03.27 |