[ 정보처리기사 ]

객체지향 설계 5대 원칙(SOLID)

히앤님 2025. 6. 25. 13:45
반응형
SMALL

SOLID는 객체지향 설계에서 유지보수성과 확장성을 높이기 위한 5가지 핵심 원칙이다.

로버트 마틴이 제안한 원칙이며 좋은 소프트웨어 설계를 위한 지침으로 널리 사용된다.

 

 

✅ 객체지향 설계 5대 원칙(SOLID)

약자 원칙 이름 의미
S 단일 책임 원칙 (Single Responsibility Principle) 클래스는 하나의 책임만 가져야 한다.
=>  한 사람은 한 가지 일만 하자!
O 개방-폐쇄 원칙 (Open/Closed Principle) 확장에는 열려있고, 수정에는 닫혀 있어야 한다.
=>  새 기능은 더하고, 원래꺼는 건드리지 말자!
L 리스코프 치환 원칙 (Liskov Substitution Principle) 자식 클래스는 부모 클래스와 호환되어야 한다.
=>  부모 대신 자식이 와도 똑같이 작동하게 하자!
I 인터페이스 분리 원칙 (Interface Segregation Principle) 사용하지 않는 기능의 의존성은 분리해야 한다.
=>  꼭 필요한 기능만을 쓰자!
D 의존성 역전 원칙 (Dependency Inversion Principle) 구체 클래스가 아니라 추상(인터페이스)에 의존해야 한다.
=> 이름이 아니라 역할로 연결하자!

 

솔-개-리-인-의

"솔개리가 인터페이스를 의심했다"

 

  • → S → 단일 책임 -> 이 클래스에 기능을 하나 더 넣어야 하는데… "단일 책임 원칙에 어긋나!"
  • → O → 개방-폐쇄 -> 기존 코드는 손대지 않고 새로운 기능을 추가만 할 수 있어야 함.
  • → L → 리스코프 -> 자식 클래스가 부모의 역할을 못 하면 리스코프 위반!
  • → I → 인터페이스 분리 -> 쓸모없는 함수들 억지로 구현해야 한다면? → 인터페이스 분리 위반.
  • → D → 의존 역전 -> "new 직접 쓰지 마! 추상화된 인터페이스를 써!"

 

 

1️⃣S - 단일 책임 원칙 (Single Responsibility Principle)

 : 하나의 사람은 한 가지 일만 해야 한다.

-> 엄마는 요리만 하고, 아빠는 운전만 해요. 엄마가 운전하고 빨래하고 청소까지 하면 힘들겠죠?

// ❌ 여러 일 하는 로봇
class Robot {
    void cook() { System.out.println("요리하기"); }
    void drive() { System.out.println("운전하기"); }
}

// ✅ 일 나눠주기
class CookRobot {
    void cook() { System.out.println("요리하기"); }
}

class DriveRobot {
    void drive() { System.out.println("운전하기"); }
}

 

 

2️⃣ O - 개방/폐쇄 원칙 (Open/Closed Principle)

: 새로운 기능은 더해서 만들고, 기존 건 바꾸지 말자!

 -> 새 게임 캐릭터를 추가하려고 할 때, 기존 캐릭터를 뜯어고치지 않아도 되는 게 좋아요!

// 인터페이스(약속)
interface Animal {
    void sound();
}

// 기존 동물
class Dog implements Animal {
    public void sound() { System.out.println("멍멍"); }
}

// 나중에 추가한 동물
class Cat implements Animal {
    public void sound() { System.out.println("야옹"); }
}

// 바꾸지 않고도 추가 가능!
class Zoo {
    void hear(Animal a) {
        a.sound();
    }
}

 

 

3️⃣L - 리스코프 치환 원칙 (Liskov Substitution Principle)

: 엄마 대신 아빠가 와도 똑같이 잘 작동해야 해요!

-> 자동차를 타야 하는데, 트럭이 와도 탈 수 있어야 해요. 근데 비행기가 오면? 안 되겠죠!

class Bird {
    void fly() { System.out.println("난다!"); }
}

class Sparrow extends Bird {
    void fly() { System.out.println("참새 난다!"); }
}

// ❌ 타조는 날 수 없는데 상속하면 문제 생김
class Ostrich extends Bird {
    void fly() { throw new UnsupportedOperationException("타조는 못 날아!"); }
}

이렇게 되면 부모 클래스(Bird)를 쓸 수 있는 곳에 자식(Ostrich)을 넣으면 문제가 생겨요. → 원칙 위반!

 

4️⃣I - 인터페이스 분리 원칙 (Interface Segregation Principle)

: 필요한 것만 골라 쓰자!

-> 나는 게임기에서 달리기만 하고 싶어! 그런데 점프, 수영, 총쏘기도 다 해야 하면 귀찮아요.

// ❌ 너무 많은 기능
interface SuperHero {
    void fly();
    void swim();
    void shoot();
}

// ✅ 나눠서 필요한 것만
interface Flyer { void fly(); }
interface Swimmer { void swim(); }

class Superman implements Flyer, Swimmer {
    public void fly() { System.out.println("하늘 날기!"); }
    public void swim() { System.out.println("헤엄치기!"); }
}

 

 

5️⃣  D - 의존성 역전 원칙 (Dependency Inversion Principle)

: 정확한 이름 말고 역할만 알려줘!

-> “게임기를 써요” → 닌텐도든 PS든 괜찮아요.
“닌텐도만 써요” → PS는 못 써요.

 

// 역할만 먼저 정해놓기
interface GameConsole {
    void play();
}

// 실제 제품
class Nintendo implements GameConsole {
    public void play() { System.out.println("닌텐도 게임!"); }
}

class Playstation implements GameConsole {
    public void play() { System.out.println("플스 게임!"); }
}

// 사용하는 사람은 '역할'만 알면 됨
class Gamer {
    GameConsole console;

    Gamer(GameConsole console) {
        this.console = console;
    }

    void startGame() {
        console.play();
    }
}
반응형
LIST