-
[C++] SOLID 법칙프로그래밍/C & C++ 2024. 10. 7. 06:05728x90반응형
SOLID는 객체지향 프로그래밍(OOP)에서 유지보수성, 확장성, 재사용성을 높이기 위한 다섯 가지 설계 원칙을 뜻합니다. 각 원칙은 소프트웨어를 더 유연하고 변경에 강하게 만들어 줍니다. SOLID는 다음 다섯 가지 원칙의 약자입니다.
1. 단일 책임 원칙 (SRP, Single Responsibility Principle)
클래스는 단 하나의 책임만 가져야 하며, 오직 하나의 이유로만 변경되어야 한다는 원칙입니다. 즉, 하나의 클래스는 하나의 기능만을 담당해야 하고, 그 기능과 관련된 변경사항이 있을 때만 수정되어야 합니다.
- 예시:
- 클래스
Report
가 데이터를 처리하고, 화면에 출력까지 한다면, 이는 두 가지 책임을 가진 것입니다. 데이터를 처리하는 역할과 화면 출력하는 역할을 나누는 것이 SRP를 따르는 방식입니다.
- 클래스
class ReportData { void Process(); // 데이터 처리 책임 }; class ReportPrinter { void Print(); // 출력 책임 };
2. 개방-폐쇄 원칙 (OCP, Open/Closed Principle)
소프트웨어 요소(클래스, 모듈 등)는 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다는 원칙입니다. 즉, 새로운 기능을 추가할 때 기존 코드를 수정하지 않고 확장할 수 있어야 한다는 의미입니다.
- 예시:
- 새로운 기능을 추가할 때 기존 코드를 수정하지 않고, 상속이나 인터페이스를 활용하여 기능을 확장하는 구조가 OCP를 따르는 설계입니다.
class Shape { public: virtual double Area() const = 0; // 인터페이스를 정의하여 확장에 열어 둠 }; class Circle : public Shape { double radius; public: double Area() const override { return 3.14 * radius * radius; } }; class Rectangle : public Shape { double width, height; public: double Area() const override { return width * height; } };
3. 리스코프 치환 원칙 (LSP, Liskov Substitution Principle)
자식 클래스는 언제나 부모 클래스를 대체할 수 있어야 한다는 원칙입니다. 자식 클래스는 부모 클래스에서 기대하는 행동을 모두 동일하게 수행할 수 있어야 하며, 부모 클래스와 자식 클래스의 관계가 치환 가능해야 합니다.
- 예시:
- 부모 클래스의 메서드를 자식 클래스에서 재정의할 때, 부모 클래스에서 기대하는 동작과 다른 동작을 수행하면 LSP를 위반하는 것입니다.
class Bird { public: virtual void Fly() {} }; class Penguin : public Bird { public: void Fly() override { // 펭귄은 날 수 없으므로 LSP 위반이 될 수 있음 throw std::logic_error("Penguins can't fly!"); } };
이 경우, 펭귄처럼 날 수 없는 새는
Bird
클래스를 상속받아서는 안 되고, 오히려 별도의 구조로 분리하는 것이 좋습니다.
4. 인터페이스 분리 원칙 (ISP, Interface Segregation Principle)
클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다는 원칙입니다. 즉, 하나의 커다란 인터페이스보다는 여러 개의 작은 인터페이스로 분리하여, 필요하지 않은 기능에 의존하지 않도록 해야 합니다.
- 예시:
- 사용하지 않는 기능까지 포함된 거대한 인터페이스보다, 각 기능별로 인터페이스를 분리하는 것이 ISP를 따르는 방식입니다.
class Printer { public: virtual void Print() = 0; virtual void Scan() = 0; }; class BasicPrinter : public Printer { public: void Print() override {} void Scan() override {} // BasicPrinter는 스캔 기능이 필요 없지만, 구현해야 함 (ISP 위반) }; // 분리된 인터페이스로 개선 class IPrinter { public: virtual void Print() = 0; }; class IScanner { public: virtual void Scan() = 0; }; class BasicPrinter : public IPrinter { public: void Print() override {} };
5. 의존성 역전 원칙 (DIP, Dependency Inversion Principle)
상위 모듈은 하위 모듈에 의존해서는 안 된다. 둘 다 추상화에 의존해야 한다는 원칙입니다. 즉, 구체적인 클래스가 아닌, 추상화된 인터페이스에 의존하게 함으로써 결합도를 낮추는 것을 목표로 합니다.
- 예시:
- 상위 클래스가 직접 하위 클래스의 구현에 의존하지 않고, 인터페이스나 추상 클래스를 통해 상호작용하는 구조를 만들면 DIP를 따르는 방식입니다.
class Keyboard {}; class Monitor {}; class Computer { Keyboard* keyboard; Monitor* monitor; public: Computer() : keyboard(new Keyboard()), monitor(new Monitor()) {} // DIP 위반: 구체적인 클래스에 의존 }; // DIP 적용 class IKeyboard {}; class IMonitor {}; class Computer { IKeyboard* keyboard; IMonitor* monitor; public: Computer(IKeyboard* k, IMonitor* m) : keyboard(k), monitor(m) {} // 추상화된 인터페이스에 의존 };
요약
- 단일 책임 원칙 (SRP): 클래스는 하나의 책임만 가져야 한다.
- 개방-폐쇄 원칙 (OCP): 클래스는 확장에 열려 있고, 수정에 닫혀 있어야 한다.
- 리스코프 치환 원칙 (LSP): 자식 클래스는 부모 클래스를 대체할 수 있어야 한다.
- 인터페이스 분리 원칙 (ISP): 클라이언트는 사용하지 않는 기능에 의존하지 않아야 한다.
- 의존성 역전 원칙 (DIP): 상위 모듈은 하위 모듈의 구현에 의존해서는 안 된다.
이 SOLID 원칙을 잘 따르는 설계는 유지보수성이 뛰어나고 확장하기 쉬운 코드가 됩니다.
728x90반응형'프로그래밍 > C & C++' 카테고리의 다른 글
[C++] 객체지향 프로그래밍(OOP, Object-Oriented Programming) (1) 2024.10.07 [C++] Forward Declaration(전방 선언) (0) 2024.07.28 [C++] const와 constexpr 차이 (4) 2024.07.23 [C++] History (C++11~20) (3) 2024.07.15 [C++] L-Value & R-Value (0) 2024.07.15 - 예시: