객체지향 프로그래밍(OOP)에서 유지보수성과 확장성을 높이기 위해 따라야 할 5가지 설계 원칙이다. 각 원칙은 소프트웨어의 가독성, 유연성, 재사용성을 강화하는 데 목적이 있다.
하나의 클래스는 하나의 책임만 가져야 한다.
목적: 클래스가 하나의 역할만 담당하도록 설계해서 변경 이유를 한 가지로 제한한다.
잘못된 설계
class Report {
void generateReport();
void saveToFile(); // 파일 저장도 책임
};
class ReportGenerator {
void generateReport();
};
class ReportSaver {
void saveToFile();
};
확장에는 열려 있고, 수정에는 닫혀 있어야 한다.
목적: 기존 코드를 수정하지 않고도 기능을 확장할 수 있도록 설계한다.
예시
class Shape {
virtual double area() const = 0;
};
class Circle : public Shape {
double area() const override { return 3.14 * radius * radius; }
};
class Rectangle : public Shape {
double area() const override { return width * height; }
};
자식 클래스는 부모 클래스를 대체할 수 있어야 한다.
목적: 다형성을 보장하고, 예상치 못한 동작을 방지한다.
잘못된 설계
class Rectangle {
virtual void setWidth(int w);
virtual void setHeight(int h);
};
class Square : public Rectangle {
void setWidth(int w) override { width = w; height = w; } // 비정상 동작
};
class Shape {
virtual double area() const = 0;
};
class Rectangle : public Shape {
double area() const override { return width * height; }
};
class Square : public Shape {
double area() const override { return side * side; }
};
클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.
목적: 큰 인터페이스를 여러 작은 인터페이스로 분리해서 불필요한 의존성을 제거한다.
잘못된 설계
class Printer {
virtual void print();
virtual void scan(); // 사용하지 않는 기능 포함
};
class Printer {
virtual void print() = 0;
};
class Scanner {
virtual void scan() = 0;
};
고수준 모듈은 저수준 모듈에 의존하지 않아야 한다. 둘 다 추상화에 의존해야 한다.
목적: 구현 세부사항이 아닌 추상화에 의존해서 유연성을 높인다.
예시
class Engine {
virtual void start() = 0;
};
class Car {
Engine* engine;
public:
Car(Engine* e) : engine(e) {}
void run() { engine->start(); }
};