HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🍗
[New] 조규현팀
/
🏪
TS Store
/
☀️
SOLID 5원칙
☀️

SOLID 5원칙

Person
완료율%
상태
완료
나의 블로그
https://morning-paprika-8fa.notion.site/SOLID-49bce62f6e9d460fb3c2e47c14d576b1
Think Sharing (TS)
🏬
SOLID
SOLID ?Single Responsibility Principle(단일 책임 원칙)여러가지 책임을 하고 있는 경우한가지 책임만 하는 경우Open-Closed Principle(개방-폐쇄 원칙)예시Liskov Substitution Principle(리스코프 치환 원칙)위반한 경우올바른 경우Interface Segregation Principle(인터페이스 분리 원칙)Dependency Inversion(의존성 역전 원칙)강하게 종속되어 있는 경우의존이 역전된 경우REF

SOLID ?

 

Single Responsibility Principle(단일 책임 원칙)

  • 클래스는, 오직 하나의 대해서만 책임져야 한다.
  • 만약 클래스가 여러가지 작업을 책임져야 한다면, 이는 버그 발생 가능성을 높이게 됩니다. 또한 많은 기능 중 한가지를 변경할 때 모르는 사이에 다른 기능에 영향을 줄 수 있기 때문이다.
  • SRP의 목적은 행동을 분리하는 것이고, 이로 인해 어떤 기능을 수정하더라도, 연관없는 기능에는 영향이 가지 않게 될 것이다.

여러가지 책임을 하고 있는 경우

  • 아래의 예시는 캐릭터가 검사일때와 궁수일때의 책임을 수행하고 있으며 두 가지의 책임을 가지고 있으며 응집도가 낮다고 할 수 있다.
  • 다른 책임과 position이라는 필드를 공유하고 있는 것처럼 의존도가 높아 결합도가 높다고 할 수 있다.
public class Character { String position; public Character(String position) { this.position = position; } public String attack() { if (position == "검사") { return "칼로 휘두른다."; } else { return "활을 쏜다."; } } }

한가지 책임만 하는 경우

  • 아래의 클래스는 추상클래스를 통해 검사와 궁수의 책임을 분리하여 각 하나의 책임만 맡고 있기 때문에 응집도가 높으며 의존도가 존재하지 않기 때문에 결합도도 낮다고 할 수 있다.
public abstract class Character { public abstract String attack(); } public class Warrior extends Character { public String attck() { return "칼을 휘두른다."; } } public class Archer extends Character { public String attck() { return "활을 쏜다."; } }

Open-Closed Principle(개방-폐쇄 원칙)

  • 클래스는 확장에는 개방적이어야 하고, 변경이는 폐쇄적이어야 한다.
  • 클래스의 현재 코드를 변경하는것은 해당 클래스를 사용하고 있는 모든 시스템에 영향을 주게 된다.
  • 만약 클래스에 더 많은 기능을 부여하고 싶다면, 가장 이상적인 접근방법은 기존 기능을 변경하는것이 아닌 새로운 함수를 추가하는 것이다.
  • OCP의 목적은 클래스의 존재하는 기능의 변경 없이 해당 클래스의 기능을 확장시키는 것이다. 이로 인해 사용중인 클래스의 변경으로 인한 버그 발생을 피할 수 있다.

예시

  • 아래는 단일책임 원칙에 사용했던 예시로 새로운 직업이 만약에 새로 생긴다 해도 다음과 같이 다른 클래스의 변경 없이 단순히 새로운 직업에 대한 클래스를 추가하기만 하면 된다.
public abstract class Character { public abstract String attack(); } public class Thief extends Character { public String attck() { return "표창을 날린다."; } }

Liskov Substitution Principle(리스코프 치환 원칙)

  • 만약 S가 T의 서브타입이라면, T는 어떠한 경고도 내지 않으면서, S로 대체가 가능하다.
  • 자식 클래스가 부모클래스의 기능을 똑같이 수행할 수 없을때, 이는 버그를 발생시키는 요인이 된다.
  • 만약 어떤 클래스가 자신으로부터 다른 클래스를 생성했다면, 이제 그 클래스는 부모 클래스가 되고, 생성된 클래스는 자식 클래스가 된다. 자식 클래스는 부모 클래스가 할 수 있는 모든 것을 할 수 있어야 한다. 이를 상속이라고 표현한다.
  • 자식 클래스는 부모 클래스처럼 똑같은 요청에 대해 똑같은 응답을 할 수 있어야 하고, 응답의 타입 또한 같아야 한다.
 

위반한 경우

public class Rectangle { int width; int height; public int getWidth() { return width; } public int getHeight() { return height; } public void setWidth(int width) { this.width = width; } public void setHeight(int height) { this.height = height; } public int getArea() { return width * height; } } public class Square extends Rectangle { @Override public void setWidth(int width) { super.setWidth(width); super.setHeight(getWidth()); } @Override public void setHeight(int height) { super.setHeight(height); super.setWidth(getHeight()); } } // 50 Rectangle rectangle = new Rectangle(); rectangle.setWidth(10); rectangle.setHeight(5); // 25 Rectangle rectangle = new Square(); rectangle.setWidth(10); rectangle.setHeight(5);
🔥
동일한 값을 넣었는데 다른 값을 반환하고 있으며 직사각형과 정사각형은 상속관계가 될 수 없는 구조이다. 사각형의 특징을 갖고 있지만 두 사각형 모두 사각형의 한 종류일 뿐이지 하나가 다른 하나를 완전히 포함하진 못한다.
 

올바른 경우

public class Shape { int width; int height; public int getWidth() { return width; } public int getHeight() { return height; } public void setWidth(int width) { this.width = width; } public void setHeight(int height) { this.height = height; } public int getArea() { return width * height; } } public class Rectangle extends Shape { public Rectangle(int width, int height) { setWidth(width); setHeight(height); } } public class Square extends Shape { public Square(int length) { setWidth(length); setHeight(length); } } // 50 Shape rectangle = new Rectangle(10, 5); // 25 Shape rectangle = new Square(5);

Interface Segregation Principle(인터페이스 분리 원칙)

  • 클라이언트는 사용하지 않는 메서드에 대해 의존적이지 않아야 한다.
  • 클래스가 서로 관계없는 기능들을 가지고 있다면 낭비가 되고, 예상치 못한 버그를 발생시킬 수 있다.
  • 클래스는 해당 역할에 대해 액션만 수행해야 하고, 이를 제외한 다른 액션은 완전히 삭제하거나 다른 곳(다른 클래스 등)으로 이동시켜야 한다.
  • ISP의 목적은 액션 집합을 더 작은 액션 집합으로 쪼개서, 클래스가 필요한 액션들만 실행할 수 있도록 하는 것이다.

Dependency Inversion(의존성 역전 원칙)

  • 추상은 구체에 의존하지 않아야 하며, 구체는 추상에 의존해야 한다.
  • 고수준의 모듈은 저수준의 모듈에 의존적이면 안되고, 둘다 추상에 의존적이어야 한다.
    • 고수준 모듈(또는 클래스) : 도구와 함께 동작하는 클래스
      • ex) 바이트 데이터를 읽어와 암호화 하고 결과 바이트 데이터를 쓴다.
    • 저수준 모듈(또는 클래스) : 수행하기 위한 도구
      • ex)
        • 파일에서 바이트 데이터를 읽어온다.
        • AES 알고리즘으로 암호화한다.
        • 파일에 바이트 데이터를 쓴다.
    • 추상 : 두 클래스를 연결하는 인터페이스
    • 구체 : 도구가 동작하는 방법
  • DIP는 액션을 수행할 때 클래스가 도구와 융합하면 안된다고 말한다. 보다 좋은 방법은 인터페이스와 융합하여 클래스와 도구를 연결하는 것이다.
  • 두 클래스와 인터페이스는 어떻게 도구가 동작하는지 알 수 없어야 한다. 하지만, 도구는 인터페이스 사양을 충족해야 한다.
  • DIP의 목적은 인터페이스를 통해 고수준 클래스이 저수준 클래스에 대해 의존성을 가지는 것을 줄이는 것이다.
 

강하게 종속되어 있는 경우

  • 코드를 아래처럼 작성한다면 키보드와 마우스에 강하게 종속된다. 즉 맥미니는 특정 키크론 키보드와 로직텍 마우스밖에 사용할 수 없게 된다 만약 이 맥미니에 키크론키보드가 아니라 다른 키보드 브랜드를 사용한다고 하면 무조건 맥미니 클래스를 수정해야 한다.
    • 즉 확장에 닫혀있고 수정에 열리게 된다.
public class MacMini { private final 키크론키보드_K3 키보드; private final 로지텍마우스_XXX 마우스; public MacMini() { 키보드 = new 키크론키보드_K3(); 마우스 = new 로지텍마우스_XXX(); } }

의존이 역전된 경우

  • 맥미니가 인터페이스에 의존하게 되면서 인터페이스를 확장한 모든것을 사용할 수 있게되며 확장에는 열리고 수정에는 닫히게 된다.
public interface Keyboard { } public interface Mouse { } public class Keychron implements Keyboard { } public class Hhkb implements Keyboard { } public class Logitech implemets Mouse { } public class Trakpad implements Mouse { } public class MacMini { private final Keyboard keyboard; private final Mouse mouse; public MacMini(Keyboard keyboard, Mouse mouse) { this.keyboard = keyboard; this.mouse = mouse; } } MacMini macmini = new MacMini(new Keychron(), new Logitech()); MacMini macmini = new MacMini(new Hhkb(), new Trakpad());

REF

The S.O.L.I.D Principles in Pictures
If you are familiar with Object-Oriented Programming, then you've probably heard about the SOLID principles. These five software development principles are guidelines to follow when building software so that it is easier to scale and maintain. They were made popular by a software engineer, Robert C. Martin.
https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898
The S.O.L.I.D Principles in Pictures
[번역] 그림으로 보는 SOLID 원칙
SOLID 원칙과 관련된 좋은 그림예시가 있어서 이를 번역하면서 예제코드를 추가하였습니다. 만약 당신이 객체지향 프로그래밍과 친숙하다면, 당신은 SOLID 원칙에 대해 들어보았을 것 입니다. 이러한 다섯가지 개발 원칙은 소프트웨어 개발과 유지보수를 쉽게 할수 있도록 하는 가이드라인이라고 볼 수 있습니다. 이러한 원칙은 Robert C. Martin이라고 하는 소프트웨어 엔지니어에 의해 유명해졌습니다.
https://blog.siner.io/2020/06/18/solid-principles/
[번역] 그림으로 보는 SOLID 원칙
[OOP] SOLID 원칙
클린코드의 저자 로버트 C.마틴이 2000년대 초, 객체지향 프로그래밍 및 설계의 다섯가지 원칙을 정의하였다. 이를 동료 개발자인 마이클 페더스가 앞글자를 따와서 정리한 것이 SOLID 이다. 응집도를 높이고, 결합도는 낮추는 원칙을 OOP 즉, 객체지향의 관점에서 재정립한 설계 원칙이다. 다음과 같은 다섯가지가 있다.
[OOP] SOLID 원칙
https://minkwon4.tistory.com/281
[OOP] SOLID 원칙
[객체지향] SOLID란?
객체지향 책에서 자주봤지만 자주 잊게되는 SOLID에 대하여 알아보겠습니다. SOLID는 Robert Martin 이 객체지향 설계를 잘 하기 위하여 모아놓은 다섯가지 원칙의 앞글자모음입니다. 이 원칙들을 꽤뚫는 핵심은 객체를 역할과 구현 으로 나누는 것 입니다. 사용자는 역할(인터페이스)만 알면 되고, 구현이 변경되어도 영향을 받지 않게 됩니다. 하나의 클래스는 하나의 책임을 가져야 합니다.
[객체지향] SOLID란?
https://chrisjune-13837.medium.com/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EA%B3%BC-solid-ac4fdbe8882
[객체지향] SOLID란?
SOLID 원칙이란
객체지향 프로그래밍 및 설계에 대한 다섯가지 기본원칙 powered by Clean Architecture 1990년대이전 개발자는 하드웨어로인한 소프트웨어의 제약사항 때문에, "유지보수성이 높은 코드" 보다는 "기기 입장에서 효율적인 코드"를 더욱 선호하는 추세였다. 하지만, 무어의 법칙 이 나올 정도로, 하드웨어가 끊임없이 발전하고 프로그래머가 소프트웨어를 키우는 속도 보다 하드웨어의 발전속도가 더 빨라지게 되자, 개발자는 하드웨어로 인한 제약사항 에서 어느정도 벗어나게 되었다.
SOLID 원칙이란
https://velog.io/@xylopeofficial/SOLID-%EC%9B%90%EC%B9%99%EC%9D%B4%EB%9E%80
SOLID 원칙이란
객체지향 개발 5대 원칙 (SOLID)
모든 개발이 그렇듯 프로젝트 초반에는 완벽하게 설계가 된것 같고 견고하게 구조를 다듬어 나아가는듯하게 개발이 되지만 개발을 하면 할수록 나의 코드와 구조의 틀이 점점 어긋나기 시작합니다. 어쩔수 없이 리팩토링을 나중에 하지만 그럴때마다 항상 떠오르는 기본중의 기본 원칙, 바로 이번에 소개하는 객체지향 개발 5대 원칙을 항상 떠올리게됩니다.
객체지향 개발 5대 원칙 (SOLID)
https://velog.io/@lsb156/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EA%B0%9C%EB%B0%9C-5%EB%8C%80-%EC%9B%90%EC%B9%99-SOLID
객체지향 개발 5대 원칙 (SOLID)