ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SOLID Principle
    IT Fundamental Concept/OOAD 2019. 12. 3. 22:12
    객체 지향 프로그래밍에서 SOLID는 소프트웨어 설계를 보다 이해하기 쉽고 유연하게 유지 관리하기 위한 5 가지 설계 원칙의 약어입니다. 이는 미국 S/W 엔지니어 Robert C. Martin에 의해 Promote된 많은 원칙 중 일부입니다. SOLID 원칙은 모든 객체 지향 설계에 적용되지만 Agile Development 또는 Adaptive Software Development과 같은 방법론의 핵심 철학을 형성되고 있습니다.  SOLID 원리에 대한 이론은 Martin이 2000년 논문 Design Principles and Design Patterns에서 소개 한 바 있으며, SOLID 약어는 나중에 Michael Feathers에 의해 소개 됩니다.

    S

    SRP (Single responsibility principle)

    단일 책임 원칙 

    “한 클래스는 하나의 책임만 가져야 한다.”

    모든 클래스는 하나의 책임만 가지며, 클래스는 그 책임을 완전히 캡슐화해야 함을 일컫는다. 클래스가 제공하는 모든 기능은 이 책임과 주의 깊게 부합해야 한다.

    • 하나의 Class 파일은 단 하나의 책임(역할)을 달성하기 위해서만 사용해야한다는 원칙이다. 또한 내부를 캡슐화 하여 외부로 부터 내용을 감추고, 외부에서 접근하는 목적도 해당 책임에 부합하는 내용이어야 한다.
    • 하나의 Class 내부에 여러 책임이 존재하면, 다양한 목적으로 소스 코드 수정이 발생하며, 상호 영향을 주어 생각지 못한 오류를 야기할 수 있다.
    • 이는 High Coheison, Low Coupling을 달성 하기 위한 기본 원칙 이다. 

     

    O

    OCP (Open/closed principle)

    개방-폐쇄 원칙  

    “소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.”

    소프트웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다'는 프로그래밍 원칙이다.

    • 객체지향 설계나 수많은 디자인 패턴에서 가장 많이 활용되는 원칙이다. 고객의 요구에 따라 변화 또는 확장이 예측되는 부분은 "Open" 시켜 놓고 수정이 발생하면 안되는 부분(Core)은 "Close"시켜 변화와 기능 확장에 유연하면서, 기존 프로그램 골격과 기능을 유지할 수 있어야 한다. 
    • OCP가 잘 적용되면, 기능을 추가하거나 변경해야 할 때 이미 제대로 동작하고 있던 원래 코드를 변경하지 않아도, 기존의 코드에 새로운 코드를 추가함으로써 기능의 추가나 변경이 가능하다.
    • 유연성, 재사용성, 유지보수성 등의 품질속성을 기대할 수 있다.
    더보기

    Question

    "변화가 예측되는 부분을 Open시켜 놓는다는 것은 무슨 뜻이죠? 어떻게 Open을 시켜 놓는다는 것인가요?"

     

    Answer

    "이는 객체 지향 언어의 대표적인 특성인 추상화(Abstraction)와 다형성(Polymorphism) 을 통해 가능 합니다.

    기본 알고리즘 또는 구조를 Abstract Class로 선언하고, 달라지는 부분은 이를 상속받은 Concrete Class에서 구현하게 됩니다. 

    Runtime 환경에서 부여받은 인스턴스에 따라 다르게 동작되는 다형성 성질에 따라, 다양한 기능이 동작되도록 구현할 수 있습니다. 

    if ~ else, switch 와 같은 조건문으로 변경될 때마다 로직을 통째로 수정하는 것이 아닌, Concrete Class 확장을 통해서 새로운 기능이 수행될 수 있도록 설계하는 것이 객체 지향에 맞는 설계 방법 입니다.

    앞으로 기대되는 기능 확장에 대해 주요 비지니스 로직은 수정되거나 영향받지 않도록 많은 고민을 하며 설계를 해야 합니다."

     

    L

    LSP (Liskov substitution principle) 

    리스코프 치환 원칙 

    프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.

    상속을 사용할 때 지켜야 하는 원칙으로써, 언제든지 Sub Type이 Base Type으로 교체될 수 있어야 함을 뜻한다. 교체될 수 있다는 것은 is-a 관계를 만족한다는 것이고, Super class의 Contract을 지켜야 한다는 것이다. 

    • 부모가 할 수 있는 일은 자식이 모두 처리 할 수 있어야 한다. 즉 부모가 실행될 수 있는 모든 곳에서 자식이 실행될 수 있어야 한다.
      ※ 우리나라에서 자식이 하는 일을 부모가 다 나서서 하자나요?? OOP에서는 반대로 부모가 하는 모든 일을 자식이 할 수 있어야 합니다.
    • 치환성(영어: substitutability)은 객체 지향 프로그래밍 원칙이다. 

    자식 Class에서 오버라이딩을 통해 메서드를 재 정의 할 때 다음 조건이 반드시 성립해야 한다. 

    • 하위형에서 선행조건은 강화될 수 없다.
    • 하위형에서 후행조건은 약화될 수 없다.
    • 하위형에서 상위형의 불변조건은 반드시 유지되어야 한다.

    “즉, 서브 클래스는 pre-condition 유지약화시키는 것만 가능하고 post-condition 유지강화 시키는 것만 가능 하다.”

    더보기

    생각해 볼 부분

    직사각형의 부모 Class가 존재한다. 

    너비와 높이의 조회(getter) 및 할당(setter) 메서드를 가진다.

    막내 개발자가 정사각형이라는 Class를 만들었는데 기존 직사각형 Class와 속성과 함수가 동일하여, 상속을 통해 클래스를 파생하였다.

    이렇게 상속해서 사용하는 경우 문제가 될까?

     

    답변

    정사각형의 특성은 분명 직사각형의 특성에 포함된다. 하지만 너비와 높이가 항상 동일하다는 추가 조건이 붙어 있다.

    부모, 직사각형 Class에서 setter메서드가 다음과 같이 정의되어 있다고 가정하자.

    class Rectangle {  

        int width;

        int height;  

        pubilc void setWidth(int width) {

            this.width = width;

        } 

        public void setHeight(int height) {

            this.height = height;

        }

    }

     

    자식, 정사각형 Class에서 setter 함수를 정사각형의 특징에 맞게 오버라이딩 하여 다음과 같이 메서드를 만들었다.

    class Square extends Rectangle {

        public void setWidth(int width) {

            super.width = width;

            super.height = height;   

        }

        public void setHeight(int width) {

            super.width = width;

            super.height = height;   

        }

    }

     

    문제가 보이는가??

     

    모든 정사각형은 직사각형이라고 할 수 있다라는 논리는 참이지만, 정사각형은 반드시 너비와 높이가 같아야 한다는 추가 조건이 성립되어야만 한다.

     

    첫번째로, 정사각형은 너비와 높이에 대한 변수를 각각 만들어 줄 필요가 없다. (메모리 낭비)

    두번째로, setWidth 또는 setHeight 중 하나의 메서드만 있어도 무방하나 불필요한 메서드를 생성하게 된다.

     

    다음 마지막 문제가 가장 중요하다.

    Rectangle 형태의 인스턴스 객체를 변수로 받아 해당 객체의 너비를 10 높이를 5로 만드는 함수가 있다고 가정하자.

    class test {

        public void makeBasicModel ( Rectangle rectangle ) {

            rectangle.setWidth(10);

            rectangle.setHeight(5);

        }

    }

     

    여기에 부모 Class인 Rectangle 인스턴스가 들어오는 경우, 정상적으로 알고리즘이 수행되지만, 자식 Class인 Square가 들어오는 경우, 너비와 높이가 모두 5인 사각형이 만들어 진다. 즉 사용자의 의도와 다른 결과를 가지게 된다. 즉 부모가 정상적으로 수행될 수 있는 곳에 자식이 정상적으로 수행될 수 없으므로 LSP 위반이라 할 수 있다.

     

    즉, 파생 클래스에 기반 클래스 보다 더 강한 요구 사항을 충족시키려고 한다면, 이를 사용하는 사용자 로직에서 오류 또는 기대하지 않은 결과를 가져올 수 있다.

     

    I

    ISP (Interface segregation principle)

    인터페이스 분리 원칙 

    특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.”

    인터페이스 분리 원칙은 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다는 원칙이다.

    • 큰 덩어리의 인터페이스들을 구체적이고 작은 단위들로 분리시킴으로써 클라이언트들이 꼭 필요한 메서드들만 이용할 수 있게 한다.
    • 내부 의존성을 약화시켜 리팩토링, 수정, 재배포를 쉽게 할 수 있다.

    쉽게 말해 클라이언트가 자신이 사용하지 않는 메서드와 의존 관계를 맺으면 안 된다는 것이다. 클라이언트가 사용하지 않는 인터페이스 때문에 영향을 받아서는 안 된다. 그러려면 API는 사용자에게 꼭 필요한 메서드만 갖는 인터페이스를 제공해야 한다. 잘못 생각하면 단일 책임의 원칙처럼 클래스를 분리하는 것으로 생각할 수 있는데 인터페이스 분리의 원칙은 각 클라이언트에 맞는 인터페이스만 분리하여 사용하는 것이다.

     

    D

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

    특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.”

    인터페이스 분리 원칙은 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다는 원칙이다.

    • 큰 덩어리의 인터페이스들을 구체적이고 작은 단위들로 분리시킴으로써 클라이언트들이 꼭 필요한 메서드들만 이용할 수 있게 한다.
    • 내부 의존성을 약화시켜 리팩토링, 수정, 재배포를 쉽게 할 수 있다.

    쉽게 말해 클라이언트가 자신이 사용하지 않는 메서드와 의존 관계를 맺으면

     


    https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84)

     

    SOLID (객체 지향 설계) - 위키백과, 우리 모두의 백과사전

    위키백과, 우리 모두의 백과사전.

    ko.wikipedia.org

     

     

    'IT Fundamental Concept > OOAD' 카테고리의 다른 글

    OO Analysis & Design  (0) 2020.03.01
    OOP Concept  (1) 2020.02.29
Designed by Tistory.