ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [디자인패턴] SOLID 원칙
    디자인패턴 2020. 12. 12. 20:33
    728x90

    SOLID 원칙

    로버트 마틴이 명명한 객체지향 프로그래밍 및 설계 기본 5대 원칙

     

    1. SRP (Single Responsibility principle; 단일 책임 원칙)

    1) 정의 : 한 클래스는 하나의 책임만 가져야 한다.

     

    2) 설명

    로버트 마틴은 'Responsibility(책임)'을 '변경하려는 이유'로 정의 한 클래스는 변경하려는 단 하나 이유만을 가져야 한다.

    ex) 보고서를 편집하고 출력하는 모듈

    이 모듈은 두 가지 이유로 변경될 수 있다. 첫 번째로 보고서의 내용 때문에 변경될 수 있다. 두 번째로 보고서의 형식 때문에 변경될 수 있다.

    이 두가지 변경은 하나는 실질적이고 다른 하나는 꾸미기 위한 매우 다른 원인에 기인한다.

     SRP에 의하면 이 문제의 두 측면이 실제로 분리된 두 책임 때문이며, 따라서 분리된 클래스로 나누어야 한다. 다른 시기에 다른 이유로 변경되어야 하는 두 가지를 묶는 것은 나쁜 설계일 수 있다.

     

    3) 장점

    • 책임 영역이 확실해지기 때문에 한 책임의 변경에서 다른 책임의 변경으로의 연쇄작용에서 자유로울 수 있다.
    • 책임을 적절히 분배함으로써 코드의 가독성 향상, 유지보수 용이라는 이점이 있다.

     

    2. OCP (Open/closed principle; 개방-폐쇄 원칙)

    1) 정의 : 소프트웨어 개체(클래스, 모듈, 함수 등)는 확장에 대해 열려있어야 하고, 수정에 대해서는 닫혀 있어야 한다

     

    2) 설명

    변경을 위한 비용은 가능한 줄이고, 확장을 위한 비용은 가능한 극대화 해야 한다.

     요구사항의 변경 or 추가가 있더라도, 기존 구성요소는 수정이 일어나지 말아야 하며, 기존 구성요소를 쉽게 확장해서 재사용할 수 있어야 한다

    OCP를 가능케 하는 중요 메커니즘은 추상화와 다형성이며, 객체지향의 장점을 극대화하는 아주 중요한 원리라 할 수 있다.

     

    3) 적용방법

    OCP 위반 OCP 적용 후
    • 변경(확장)될 것과 변하지 않을 것을 엄격히 구분한다
    • 이 두 모듈이 만나는 지점에 인터페이스를 정의한다
    • 구현 클래스에 의존하기보다 정의한 인터페이스에 의존하도록 코드를 작성한다

    4) 장점

    • 객체지향 프로그래밍의 가장 큰 장점인 유연성, 재사용성, 유지보수성을 얻을 수 있다.

     

    3. LSP (Liskov substitution principle; 리스코프 치환 원칙)

    1) 정의 : 상위 타입의 객체를 하위 타입의 객체로 치환해도, 프로그램은 정상적으로 동작해야 한다

     

    2) 설명

    서브 타입은 언제나 기반 타입과 호환될 수 있어야 한다 서브 타입은 기반 타입이 약속한 규약 (public 인터페이스, 물론 메소드가 던지는 예외까지 포함)을 지켜야 한다

     

    ex) LSP 위반 예제 - Rectangle(직사각형), Square(정사각형)

    // 직사각형
    class Rectangle {
    	int width = -1;
        int height = -1;
        
        public getWidth() {
        	return this.width;
        }
        public setWidth(int w) {
        	this.width = w;
        }
    	public getHeight() {
        	return this.height;
        }
        public setHeight(int h) {
        	this.height = h;
        }
        public getArea() {
        	return this.width * this.height;
        }
    }
    // 직사각형을 상속하는 정사각형
    class Square extends Rectangle {
        @Override
        public setWidth(int w) {
        	this.width = w;
            this.height = w;
        }
        @Override
        public setHeight(int h) {
        	this.width = h;
            this.height = h;
        }
    }

    Rectangle(직사각형) 클래스가 있고, Rectangle을 상속하는 Square(정사각형) 클래스가 있다.

     

    Rectangle rec = new Rectangle();
    rec.width = 3;
    rec.height = 4;
    System.out.print(rec.area == 12); // true (Rectangle을 사용)
    
    Rectangle rec2 - new Square();
    rec2.width = 3;
    rec2.height = 4;
    System.out.print(rec2.area == 12) // false (Square을 사용)

    부모인 Rectangle 객체에서는 작동하는 행위가 Square 객체에 대해서 작동하지 않는다는 것은 LSP를 위반하는 것이다.

    'Square(정사각형) is a Rectangle(직사각형)' 라고 생각해서 코드에 상속 관계를 반영할 수 있지만, SOLID 법칙의 기준으로 보면 둘은 코드에서 상속관계로 존재할 수 없다.

    정사각형-직사각형 관계보다 더 포괄적인 Shape(도형)을 상속하도록 리팩터링 하고, 하위 클래스는 상위 클래스에서 정의한 원칙에 벗어나지 않도록 해야 한다.

     

    3) 장점

    • LSP는 규약을 준수하는 상속 구조를 제공한다 → LSP는 상속 구조가 다형성을 위해 사용될 수 있도록 해주며 OCP의 기반이 된다.

     

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

    1) 정의 : 특정 클라이언트를 위한 여러 개의 구체적인 인터페이스가, 하나의 범용 인터페이스보다 낫다

     

    2) 설명

    클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다는 원칙

     큰 덩어리의 인터페이스들을 구체적이고 작은 단위들로 분리시킴으로써 클라이언트들이 꼭 필요한 메서드들만 이용할 수 있게 한다

     

    3) 적용 방법

    ISP 위반 ISP 적용 후

    4) 장점

    • 시스템의 내부 의존성을 약화시켜 리팩토링, 수정, 재배포를 쉽게 할 수 있다

     

    5. DIP (Dependency inversion principle; 의존관계 역전 원칙)

    1) 정의 : 추상화에 의존해야지, 구체화에 의존하면 안 된다

     

    2) 설명

    • 하위 모듈의 변경이 상위 모듈의 변경을 요구하는 전통적인 의존 관계를 역전 → 상위 모듈이 하위 모듈의 구현으로부터 독립
    • 상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 동일한 추상화에 의존해야 한다.
    • Dependency Injection은 이 원칙을 따르는 방법 중 하나

    잘 구조화된 객체지향 아키텍처들은 각 레이어마다 잘 정의되고 통제되는 인터페이스를 통한 긴밀한 서비스들의 집합을 제공하는 레이어들로 구성되어 있다.

    상위 레벨의 레이어가 하위 레벨의 레이어를 바로 의존하게 하는 것이 아니라, 이 둘 사이에 존재하는 추상 레벨을 통해 의존해야 한다.

     

    3) 장점

    • 상위 레벨의 모듈은 하위 레벨의 모듈로의 의존성에서 벗어나 그 자체로 재사용되고 확장성도 보장받을 수 있다.

     

    헐리우드 원칙
    과거 헐리우드에서는 배우들이 좋은 영화의 배역을 구하기 위해 영화제작사에 자주 전화를 걸었다고 한다.
    배우들의 잦은 전화 때문에 영화기획사 담당자들이 자신의 업무를 할 수 없을 정도로 전화에 시달리게 됐다.
    고민 끝에 이들은 한 가지 좋은 묘안을 생각해 냈다. 배우들에게 자신이 어떤 역할을 잘하며 어떤 영화 배역을 맡고 싶다고 등록하도록 한다.
    기획 중인 영화에서 어떤 배역이 나왔을 때 배우가 등록한 목록에서 적합한 배우를 찾은 다음 그 배우에게 전화하면 캐스팅이 시작된다
    • 과거에는 배역을 원하는 소스(배우)들에게 능동적으로 배역을 요청/확인하게 하였고, 배역을 제공하는 타겟(영화기획사)은 수동적으로 전화가 올 때 정보를 제공했다. 이 상황에서 당연히 배우들이 아쉬운 입장이므로 전화 빈도수가 높아지고 기획사는 괴로워진다.
    • 반면 헐리우드 원칙을 도입했을 때 배우는 기획사에 자신의 정보를 등록하면 될 뿐이고 기획사는 필요한 배우에게 캐스팅을 요청하면 될 뿐이다.

     

    참고

     

     

     

     

     

    디자인패턴 - Dependency Injection 게시글 보기

    2020/12/05 - [디자인패턴] - DI (Dependency Injection) : 의존성 주입

     

    DI (Dependency Injection) : 의존성 주입

    1. 의존성 (Dependency) class Americano {...} class Programmer { private Americano americano; public Programmer() { this.americano = new Americano(); } public startProgramming() { this.americano.drin..

    waves123.tistory.com

     

     

    728x90

    '디자인패턴' 카테고리의 다른 글

    DI (Dependency Injection) : 의존성 주입  (2) 2020.12.05
Designed by Tistory.