📚 디자인 패턴과 SOLID 원칙
![](https://blog.kakaocdn.net/dn/ziXDW/btsL91dkQ40/G2eRxkxmZLwyaLWit5pZmK/img.jpg)
-
디자인 패턴은 특정 원칙을 기반으로 하여 여러 프로그래머들이 정립한 개념으로, 다양한 관련 서적이 존재하지만 모두 초기로부터 시작되었다는 점이 중요하다.
-
SOLID 원칙은 소프트웨어 개발에 있어서 구조와 유지보수의 용이성을 높이는 중요한 원칙으로, 이를 따르면 코드가 깔끔해지는 효과가 있다.
-
SOLID 원칙은 다섯 가지의 약자로 구성되며, 단일책임 원칙, 개방 원칙, 스크립트 원칙, 인터페이스 분리 원칙, 의존 역전 원칙이 이에 해당한다.
🎮 단일 책임 원칙 이해하기
![](https://blog.kakaocdn.net/dn/qq5zI/btsL9bnlWh4/TbrC9Z5K9kYarklZtuCG90/img.jpg)
-
단일 책임 원칙(Single Responsibility Principle)은 모든 클래스가 하나의 책임만 맡는 것을 의미한다.
-
이 원칙을 지키면 클래스의 기능이 명확해지고, 가독성이 향상된다.
-
예를 들어, 매쉬 렌더러는 렌더링만 하고, 오디오 소스는 오디오 출력만 하는 식으로 각 역할을 명확히 한다.
-
플레이어 클래스 안에 여러 기능을 모두 넣는 대신, 각 기능을 담당하는 클래스를 분리하면 코드의 재사용성이 높아진다.
-
단일 책임 원칙을 지키면 팀원 간의 코드 리뷰에서도 긍정적인 피드백을 받을 가능성이 높아진다.
📏 개방 폐쇄 원칙 이해하기
![](https://blog.kakaocdn.net/dn/AUS3b/btsL984vbKv/E8SDPkWPbpMCa2almxklUk/img.jpg)
-
개방 폐쇄 원칙(Open-Closed Principle)은 모듈이 확장에 열려 있지만 수정에는 닫혀 있어야 한다는 원칙이다.
-
기존의 코드를 수정하지 않고도 새로운 기능을 추가할 수 있는 구조를 유지하는 것이 중요하다.
-
예를 들어, 도형의 부피를 계산하는 프로그램에서 다양한 도형을 추가하는 경우, 기본 계산기 코드는 손대지 않고 추상 메소드를 활용하여 새로운 도형을 확장할 수 있다.
-
이러한 원칙을 지키면 복잡한 상황에서도 시스템을 쉽게 확장할 수 있다.
-
실제 라이브러리와 같은 소프트웨어들에서도 이 원칙이 잘 지켜지고 있으며, 객체지향 프로그래밍의 근본 원리로 작용한다.
-
개방 폐쇄 원칙은 확장에는 열려 있고 수정에는 닫혀 있어야 한다는 원칙이다.
-
모듈 동작을 확장하며, 보통 상속을 통해 추가 기능을 마련할 수 있다.
-
요구 사항 변경 시 새로운 동작을 추가하여 모듈을 확장할 수 있도록 하는 것이 중요한데, 이를 통해 모듈을 수정하지 않고도 변경 가능하다.
-
라이브러리를 사용할 때 기존 코드를 수정하지 않고 기능을 확장하는 것이 개방 폐쇄 원칙의 적용 예시이다.
-
이러한 원칙 덕분에 라이브러리가 DLL 형태로 배포될 수 있다.
-
도형의 부피를 계산하는 프로그램 구현 시, 각 도형을 위한 개별적인 함수 추가는 수정의 번거로움을 초래한다.
-
도형이 추가될 때마다 프로그램을 수정해야 하는 불편함이 발생하므로, SOLID 원칙의 적용이 필요하다.
-
추상 메소드를 활용하여 도형 클래스를 설계하면, 새로운 도형 추가 시 기존 계산기에 영향을 주지 않고 구현할 수 있다.
-
이론적으로 간단한 예를 통해 SOLID 원칙을 설명하였으나, 이를 실제 복잡한 상황에도 적용할 수 있음을 강조한다.
-
리스코프 치환 원칙은 파생 클래스가 기본 클래스를 대체할 수 있어야 한다는 규칙이다. 그러나 이 정의만으로는 개념이 와닿지 않을 수 있다.
-
상속받은 클래스는 부모 클래스의 규칙을 준수해야 하며, 기능을 제거하는 것이 아니라 확대하는 것이 중요하다.
-
상속을 사용할 때 기능 추가와 확장을 고려해야 하지만, 불필요한 복잡성을 피하고 규칙을 지켜야 한다.
-
클래스를 설계할 때는 클래스의 계층 구조가 항상 현실의 분류를 정확하게 나타내지 않는다는 점을 유념해야 한다.
-
예를 들어, 자동차와 기차는 서로 다른 속성을 가질 수 있지만, 단순히 상속의 관계로 묶기 어려운 복잡성이 있다.
-
상속은 클래스를 통해 기능을 물려받는 것이고, 인터페이스는 특정한 기능을 구현하는 개념이다.
-
예를 들어, 비클 클래스를 상속받아 카와 트럭을 만들 수 있지만, 이들은 기본적인 차량 기능을 탐색할 수 있다.
-
하지만 철도에서 움직이는 트레인의 경우, 도로에서의 복잡한 동작을 구현하기 어려워 상속 형태로 다룰 수 없다.
-
이러한 복잡성을 해결하기 위해 인터페이스를 사용하면, 특정 기능만 구현하면 되므로 더 유연한 설계가 가능하다.
-
따라서, 필요한 기능에 대해 각기 다른 인터페이스를 정의하고 이를 조합함으로써 SOLID 원칙을 준수할 수 있다.
-
인터페이스와 상속은 유니티의 확장성 있는 디자인을 가능하게 해준다.
-
유니티의 컴포넌트는 이러한 기법이 자주 적용되며, 이는 모든 엔진과 소프트웨어에서 통용되는 원칙이다.
-
다양한 인터페이스를 활용하여 UI 관련 코드를 구성하는 것이 가능하며, 버튼의 다양한 조합 및 역할 분담이 이루어진다.
-
이 원칙을 이해하면 유니티뿐만 아니라 다른 소프트웨어를 사용할 때도 큰 도움이 된다.
-
역할에 따라 인터페이스를 나누고, 객체를 조립하는 방식이 효과적이다.
🛠️ 인터페이스 분리 원칙과 의존 역전의 원칙
![](https://blog.kakaocdn.net/dn/I5RY8/btsL7SCf1ya/A6yGlnS5olFo0spjijvlo0/img.jpg)
-
인터페이스 분리 원칙은 클라이언트가 사용하지 않는 메서드에 의존하지 않도록 큰 인터페이스를 작게 나누어야 한다는 법칙이다. 이를 통해 시스템의 이성이 약해지고 유연성과 장기성이 향상될 수 있다.
-
유닛처럼 여러 기능(체력, 방어력 등)을 다루는 경우, 각 기능을 적절히 세분화하여 인터페이스를 구성해야 한다. 이는 각 기능을 모듈화하여 관리하는 데 도움이 된다.
-
의존 역전의 원칙은 소프트웨어 모듈을 직접 사용하지 않고 서로 추상화된 형태로 의존해야 한다는 내용을 포함한다. 상위 모듈이 하위 모듈에 의존해서는 안 되며, 서로 간접적으로 의존해야 한다.
-
클래스 간 직접적인 연관이 많아질 경우 커플링이 증가하게 되며, 이는 코드 수정 시 의존 관계로 인해 어려움을 발생시킬 수 있다. 따라서 최대한 강한 묶음 관계를 피하고, 추상화된 형태로 설계하는 것이 좋다.
-
추상 클래스와 인터페이스의 차이로는, 추상 클래스는 변수와 메서드를 포함할 수 있지만, 인터페이스는 구현 없이 선언만 가능하다는 점이다. 이러한 차이점을 이해하고 활용하여 코드 설계의 효율성을 높이는 것이 중요하다.
-
인터페이스 분리 원칙은 클라이언트가 사용하지 않는 메서드에 의존하지 않아야 한다는 법칙이다.
-
큰 덩어리의 인터페이스를 작게 쪼개고, 꼭 필요한 것만 사용해야 한다.
-
시스템 내부의 이성을 약화시켜 유연성과 장성을 강화할 수 있다.
-
예를 들어, 전략 시뮬레이션 유닛을 만들 때 체력이나 방어력 등 여러 역할을 세분화해서 나누면 코드가 깔끔해진다.
-
하지만 인터페이스를 너무 잘게 쪼개지 않아야 하며, 적당한 선을 유지하는 것이 중요하다.
-
의존 역전 원칙은 상위 모듈이 하위 모듈을 직접 사용하지 않고, 추상화에 의존해야 한다는 원칙이다.
-
클래스 간의 직접적인 의존성을 피할 필요가 있으며, 그로 인해 커플링을 최소화해야 한다.
-
서로의 의존성이 높아지면 코드 수정을 할 때 다른 클래스도 수정해야 하는 어려움이 발생한다.
-
의존 역전 원칙을 이해하기 쉽게 설명하기 위해 스위치와 문의 예시를 들어, 스위치가 직접 문에 의존하는 구조는 바람직하지 않다고 강조한다.
-
대신, 인터페이스를 활용하여 스위치가 여러 다른 구현체를 사용할 수 있도록 하면 코드 확장성과 유연성을 확보할 수 있다.
-
추상 클래스와 인터페이스는 상속을 통해 구현할 때 중요한 개념이지만, 그 차이를 이해하는 것이 필요하다.
-
클래스를 상속받을 때 부모 클래스와 구체 클래스 간의 관계를 통해 이즈 관계로 설명할 수 있다.
-
추상 클래스는 기본적으로 클래스 특성을 가지며, 필드나 멤버, 메소드를 자유롭게 구현할 수 있다.
-
다중 상속이 가능한 C++와 달리, #은 다중 상속이 불가능하여 한 가지만 선택해야 하는 제약이 있다.
-
상속 구조에서 각각의 클래스를 어떻게 연결할지 고민이 필요한 경우가 발생할 수 있다.
-
C++의 다중 상속 문제는 다이어몬드 상속으로 인해 발생하며, 이는 SOLID 원칙을 위배할 수 있다.
-
C#에서는 이러한 문제를 회피하기 위해 다중 상속을 금지하고 인터페이스를 활용하도록 설계되었다.
-
상대적으로 젊은 언어들은 다중 상속을 막고 대신 인터페이스를 제공하여 객체 간의 관계를 명확하게 설정할 수 있도록 한다.
-
추상 클래스는 메소드를 완전하게 구현하거나 일부만 구현할 수 있지만, 인터페이스는 선언만 가능하여 직접 구현할 수는 없다.
-
인터페이스는 변수나 필드를 선언할 수 없지만, 추상 클래스는 이를 사용할 수 있으며 정적 멤버와 생성자도 지원한다.
🌟 SOLID 원칙 개요 및 중요성
![](https://blog.kakaocdn.net/dn/beCDRT/btsL8IzfsAd/KS3Ao86M2xu9XmHkKrGaR0/img.jpg)
-
SOLID 원칙은 엔진 개발에서도 적용되고 있으며, 특히 UI 버튼의 구조에서 그 예를 찾아볼 수 있다.
-
추상 클래스와 인터페이스는 SOLID 원칙을 준수하기 위해 각각의 역할을 명확히 하며, 인터페이스는 다양한 동작을 수행하도록 나눠져 있다.
-
SOLID 원칙의 각 요소는 다음과 같다:
-
단일책임 원칙: 클래스는 한 가지 작업만 수행해야 하며.
-
개방-폐쇄 원칙: 기존의 기능을 수정하지 않고도 확장될 수 있어야 한다.
-
리스코프 치환 원칙: 하위 클래스는 기본 클래스를 대체해야 하며, 기본 클래스의 방향성을 유지해야 한다.
-
인터페이스 분리 원칙: 인터페이스는 작게 유지해야 하며 필요한 것만 구현해야 한다.
-
의존 역전 원칙: 구체 클래스보다 추상화에 의존해야 한다.
-
SOLID 원칙을 준수하면 디자인 패턴을 적용할 때 자연스럽게 설계에 통합되며, 이는 모든 소프트웨어 개발에 필요한 기본 이론이다.