ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 객체지향 5원칙 SOLID
    Java 2023. 11. 23. 15:42

    객체지향 5원칙

    올바른 객체지향 설계를 위해 수립한 5가지 원칙을 객체지향 5원칙(SOLID)라고 한다.
    필수로 적용하지는 않지만, 적어도 이 규칙을 준수하게 되면 올바른 객체지향 설계를 할 수 있다.

    1. 단일 책임 원칙 (Single Responsibility Principle)

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

    3. 리스코프 치환 원칙 (Liskov Substitution Principle)
    4. 인터페이스 분리 원칙 (Interface Segregation Principle)

    5. 의존성 역전 원칙 (Dependency Inversion Principle)

    단일 책임 원칙(SRP)

    SRP는 Single Responsibility Principle 의 약자로 객체는 단 하나의 책임만 가져야 한다는 원칙을 말한다.

    여기서 '책임'의 의미는 하나의 '기능'을 의미한다.

    즉, 하나의 클래스는 하나의 기능만을 담당해서 하나의 책임을 수행하는데 집중되어야한다는 것이다.

    SRP를 통해서 응집도는 높이고 결합도는 낮출 수 있게 된다.

    응집도 : 모듈이 독립적인 기능으로 정의되어 있는 정도를 의미
    결합도 : 모듈간에 상호 의존하는 정도 또는 두 모듈사이의 연관 관계를 의미

     

    pulbic class SuperMarket {
    
        private String owner;   // 주인
        private String snack;   // 과자
        private int snackCount; // 과자 갯수
    	
        /* 위배 */
        public void fnPay() {}           // 결제
        public void fnMoneyCharge() {}  // 카드 충전
        
    }

    SRP원칙에 기반해서 SuperMarket 클래스에는 슈퍼마켓의 정보만 담고 있어야하지만,

    행동을 의미하는 결제와 카드충전 메서드가 같이 있기 때문에 SRP원칙에 위배가 된다.

    pulbic class SuperMarket {
        private String owner;   // 주인
        private String snack;   // 과자
        private int snackCount; // 과자 갯수
    	
    }
    --------------------------------------------------------------
    public class Payment {
        public void fnPay() {} // 결제
        ...
    }
    --------------------------------------------------------------
    public class MoneyCharge {
        public void fnMoneyCharge() {}  // 카드 충전
        ...
    }

    위와 같이 클래스를 나눠서 만들게 된다면 SRP원칙에 맞게 하나의 클래스에 하나의 책임만 갖게 된다.

    SRP원칙에 맞게 클래스를 설계하면 다른 클래에서 결제라는 메서드가 필요할 때 슈퍼마켓 클래스를 경유할 일도 없어지게 되어 각 클래스 간 결합도가 줄어들게 들고, 응집도는 올라가게 된다.

     

    개방 - 폐쇄 원칙 (OCP)

    개방폐쇄 원칙(OCP)은 Open-Closed Principle의 약자로 기존의 코드를 변경하지 않으면서, 기능을 추가할 수 있도록 설계가 되어야 한다는 원칙이다.

    보통 확장에 대해서는 개방적(Open)이고, 수정에 대해서는 폐쇄적(Closed)이어야 한다는 의미로 정의한다.

    즉, 클래스에 기능을 추가를 위한 클래스 확장을 손쉽게 구현하면서, 확장에 따른 클래스 수정은 최소화하도록 프로그램을 작성하는 설계 기법이다.

    Open

    모듈의 확장에 열려있다.

    새로운 변경사항이 있을 때 유연하게 코드를 추가하여 클래스를 확장시킬 수 있다.

    Closed

    객체를 직접적으로 수정하는 것은 제한해야 함을 의미한다.

    새로운 변경 사항이 발생했을 때 객체를 직접적으로 수정해야 한다면 유연하게  대응할 수 없는 어플리케이션이다.

    객체를 직접 수정하지 않고도 변경사항을 적용할 수 있도록 설계해햐함을 말한다.

     

    복잡하게 설명한 것 같지만 OCP는 사실 추상화를 말한다.

    상속이나 인터페이스를 이용한다면 기존 코드를 크게 수정할 필요없이 유연하게 확장할 수 있게 된다.

    OCP의 원칙을 가장 잘 따르는 예시인 JDBC

     

     

    리스코프 치환 원칙 (LSP)

    LSP는  Liskov Substitution Principle의 약자로 부모 객체와 자식 객체가 있을 때 부모 객체를 호출하는 동작에서 자식 객체가 부모 객체를 완전히 대체할 수 있다는 원칙을 말한다.

    객체지향 프로그래밍에서는 상속을 하게되면 하위타입인 자식객체는 상위타입인 부모 객체의 특성을 가지며 그 특성을 토대로 확장할 수 있는데, 리스코프 치환 원칙은 올바른 상속을 위해 자식 객체의 확장이 부모 객체의 방향을 온전히 따르도록 권고하는 원칙이다.

     

    인터페이스 분리 원칙 (ISP)

    ISP는 (Interface Segregation Principle)의 약자로 객체는 자신이 사용하는 메서드에만 의존해야 한다는 법칙이다.

    인터페이스는 광범위하게 많은 기능을 구현하면 안되며, 인터페이스를 사용하는 객체를 기준을 작게 분리되어야 한다는 의미이다.

    ISP 위반 사례

    User1오 오직 op1 메서드만을 사용하게 될 경우,
    User1은 OPS 전체를 상속받았기 때문에 op2, op3 메서드를 사용하지 않더라도 갖고 있는 것이 된다.

    이렇게 된다면 op2 메서드가 변경되었을 때 함께 변경되어 재컴파일과 재배포등의 과정이 같이 일어나게 되면서 불필요한 낭비를 하게 된다.

    ISP 적용 사례

     

    위와 같이 ISP를 적용하게 된다면, op2의 메서드가 변경된다 하더라도 다른 User객체들에게는 영향을 주지 않게 되기에 불필요한 낭비를 줄이며 독립적인 객체를 만들 수 있게 된다.

     

    즉, ISP는 반드시 객체가 자신에게 필요한 기능만을 갖도록 제한하는 원칙으로 객체의 불필요한 책임을 제거한다.

     

    의존성 역전 원칙 (DIP)

    DIP는 Dependency Inversion Principle의 약자로 고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다는 원칙이다.

    여기서 고수준 모듈은 인터페이스와 추상클래스 같은 단일 기능을 제공하는 모듈을 의미하고,
    저수준 모듈은 메인클래스, 객체와 같은 고수준 모듈의 기능을 구현하기 위한 기술적인 세부사항이나 구현을 나타낸다.

    즉, 구체화에 의존하는 것이 아닌 추상화에 의존해야한다는 것이다.

     

    고수준 클래스가 저수준 클래스를 사용하기 때문에 고수준 클래스가 저수준 클래스에 의존하는 것이 자연스러워 보이지만 저수준 클래스는 빈번하게 변경하되고 새로운 것이 추가될 때마다 고수준 클래스에 영향을 미칠 수 있기에 의존관계를 역전시켜야 한다.

    자신보다 변하기 쉬운 것에 의존해서는 안된다!

     


    참고자료

    https://inpa.tistory.com/entry/OOP-%F0%9F%92%A0-%EC%95%84%EC%A3%BC-%EC%89%BD%EA%B2%8C-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-SRP-%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99#%EB%8B%A8%EC%9D%BC_%EC%B1%85%EC%9E%84_%EC%9B%90%EC%B9%99_-_srp_single_responsibility_principle

     

    https://yoongrammer.tistory.com/96

     

    https://blog.itcode.dev/posts/2021/08/13/single-responsibility-principle

     

    https://velog.io/@harinnnnn/OOP-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-5%EB%8C%80-%EC%9B%90%EC%B9%99SOLID-%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99-LSP


    https://velog.io/@harinnnnn/OOP-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-5%EB%8C%80-%EC%9B%90%EC%B9%99SOLID-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%B6%84%EB%A6%AC-%EC%9B%90%EC%B9%99-ISP


    https://velog.io/@harinnnnn/OOP-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-5%EB%8C%80-%EC%9B%90%EC%B9%99SOLID-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%97%AD%EC%A0%84-%EC%9B%90%EC%B9%99-DIP

    'Java' 카테고리의 다른 글

    Java 입출력 Scanner와 BufferedReader  (0) 2023.11.26
    @Bean과 @Component  (1) 2023.11.24
    @Transactional이란 무엇인가  (0) 2023.11.22
    생성자 주입(Constructor Injection)을 권장하는 이유  (1) 2023.11.20
    Early Return  (0) 2023.11.18
Designed by Tistory.