소프트웨어공학

객체지향 설계원칙(SOLID)_클래스 설계 SRP, OCP, LSP, ISP, DIP, 패키지응집성 REP,CCP, CRP, 패키지결합성 ADP, SDP, SAP

스윙스윙 2021. 10. 17. 18:46

▣ 객체지향 설계원칙(SOLID)_클래스 설계 SRP, OCP, LSP, ISP, DIP, 패키지응집성 REP,CCP, CRP, 패키지결합성 ADP, SDP, SAP

용어 개념
단일 책임 원칙
(SRP, Single responsibility principle)
'하나의 클래스 하나의 책임만 가져야 한다'
클래스는 그 책임을 완전히 캡슐화해야 함을 의미
EX) 자동차 클래스는 자동차 기능만 제공해야지, 비행기 기능도 제공하면 안됨
개방 폐쇄 원칙
(OCP, Open/closed principle)
소프트웨어 요소는 확장에는 열려있으나 변경에는 닫혀 있어야 함
변하는 것과 변하지 않는 것을 구분한 후, 변해야 하는 것은 쉽게 변할 수 있게하고 변하지 않아야 할 것은 변하는 것에 영향을 받지 않게 하는 것
클래스를 변경하지 않고도 대상 클래스의 환경을 변경할 수 있는 설계가 되어야 함
특히 단위 테스트를 수행할 때 매우 중요함
리스코프 치환 원칙
(LSP, Liskov substitution principle)
'원래 하기로 정한 것을 바꾸지 말아라'
자식클래스는 최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야 함
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 서브타입(하위클래스)은 어디서나 자신의 기반타입(상위클래스) 인스턴스로 바꿀 수 있어야 함
부모 클래스에서 상속받은 메서드들이 자식 클래스에 오버라이드, 즉 재정의하지 않는 것
인터페이스 분리 원칙
(ISP, Interface segregation principle)
'하나의 인터페이스를 여러 클래스가 공유하지 말아라'
인터페이스를 클라이언트에 특화되도록 분리시키라는 것으로 범용의 공통적인 인터페이스를 여러 클래스가 공유해서 사용하지 말라는 것
특정 클라이언트를 위한 인터페이스
 여러 개가 범용 인터페이스 하나보다 낫다.
의존관계 역전 원칙
(DIP, Dependency inversion principle)
'무언가 의존할 때, 구체 클래스에 의존하지 말고 인터페이스에 의존해라'
추상화에 의존
해야지, 구체화에 의존하면 안된다
의존 관계를 맺을 때 변하기 쉬운것 또는 자주 변하는 것 보다는 변화하기 어려운 것 또는 거의 변화가 없는 것에 의존해야 함

 

■ 패키지 응집성 원칙

REP(The Reuse Release Equivalence Principle) : 재사용의 단위는 릴리즈의 단위와 동일해야 함

릴리즈 단위란 실제 컴파일되어 배포되는 단위를 말함

(a.exe, b.lib, c.lib 배포시 b.lib, c.lib 단위로 재사용 할 수 있지만 b.lib안에 들어있는 작은 클래스 단위로 재사용하게 만들지 말라는 의미)

하나의 컴포넌트는 하나의 릴리즈 단위로 배포됨

 

CCP(The Common Closure Principle) : 패키지 안의 클래스들은 같은 종류 변경에 닫혀 있어야 함

패키지 안의 모든 클래스들은 같은 변경과 관련이 있어야 함

(패키지 안의 A,B,C 클래스 있는데, A클래스 변경이 발생했다면 B, C클래스도 변경되어야 함)

밀접한 클래스들만 모아서 패키지 구성

 

CRP(The Common Reuse Principle) : 패지키 안의 클래스들은 모두 함께 재사용되어야 함

(패키지 안의 A,B,C가 있는데, A만을 재사용한다는 말은 패키지 안의 모든 클래스 A,B,C를 재사용해야 한다는 의미)

 

 

■ 패키지 결합성 원칙

ADP(The Acyclic Dependencies Principle)

패키지 의존성 그래프에 순환이 있으면 안됨

순환구조를 갖는 컴포턴트들은 하나의 거대한 컴포넌트가 됨

단위테스트를 하고 릴리스 하는 일도 굉장히 어려워지며 에러도 쉽게 발생함

모듈의 개수가 많아짐에 따라 빌드 관련 이슈도 기하급수적으로 증가함

 

SDP(The Stable Dependencies Principle)

더 안정된 것에 의존하라. 의존 방향은 안전성의 방향으로 되어야 함

변동성이 낮은 것은 안정성이 높다고 표현

불안정성 I = Fan-out/ (Fan-in + Fan-out) [0, 1] 범위값을 갖음

 0 이면 최고로 안정된 컴포넌트, 1이면 최고로 불안정한 컴포넌트

 

SAP(The Stable Abstractions Principle)

컴포넌트는 안정된 정도만큼만 추상화되어야 함

Abstractness(A) : 패키지의 추상화 정도 (1에 가까울수록 패키지내에 Abstract class가 많음)

 

A = (abstract class) / (total class)

Stable Abstraction Principle에 의해 stable 할수록 abstract level이 높아야 함

I가 낮을수록 (Stable할수록) A가 높아야 함

-> Main sequence : A+I = 1 (Main sequence에 가까울수록 좋음)

 

D(distance) = |A + I - 1| (distance가 0에 가까울수록 좋음)

 


2019년 29번

정답 : 3번

 

3개의 패키지, 3개의 클래스, 2개의 인터페이스

패키지는 크게 의미가 없으므로 클래스와 인터페이스만 집중적으로 보면 됨

문제에 나온 관계는 의존관계와 실체화 관계의 2가지임

 

* 의존 관계는 사용 관계, 실체화 관계는 인터페이스를 클래스로 구현하는 관계임

 

OrderUI클래스는 IOrderProcessing 인터페이스와 의존관계를 맺고 있음

인터페이스는 인터페이스일 뿐이므로 실제 동작을 구현한 클래스가 필요함

그 구현의 클래스는 FastOrderMgr임

FastOrderMgr클래스는 IOrderData인터페이스와 의존관계를 맺고 있음

그 구현의 클래스는 OrderRepository임

 

의존관계 역전 원칙(DIP, Dependency inversion principle)

'무언가를 의존할 때, 구체 클래스에 의존하지 말고 인터페이스에 의존해라'라는 원칙

 

 

 

 

 


2019년 33번

정답 : 3번

객체지향 프로그래밍에서는 일반적으로 하나의 패키지는 하나의 컴포넌트로 개발함

 

패키지 응집성 원칙

REP(The Reuse Release Equivalence Principle) : 재사용의 단위는 릴리즈의 단위와 동일해야 함

CCP(The Common Closure Principle) : 패키지 안의 클래스들은 같은 종류 변경에 닫혀 있어야 함

CRP(The Common Reuse Principle) : 패지키 안의 클래스들은 모두 함께 재사용되어야 함

 

SCP는 응집성 원칙이 아님

 


2021년 26번

정답 : 2번

문제 지문에 '변경'이라는 단어가 나왔으므로,

가장 가까운 원칙은 개방-폐쇄 원칙(OCP, Open Closed Principle) 임

 

OCP에 위반하지 않은 설계를 할 때 가장 중요한 것은 무엇이 변하는 것인지, 

무엇이 변하지 않는 것인지를 구분해야 한다는 점이다.
변해야 하는 것은 쉽게 변할 수 있게 하고, 변하지 않아야 할 것은 변하는 것에 영향을 받지 않게 해야 한다.
클래스를 변경하지 않고도 대상 클래스의 환경을 변경할 수 있는 설계가 되어야 한다.
특히 단위 테스트를 수행할 때 매우 중요함

 


2021년 48번

정답 : 4번

인터페이스가 2개로 갈라져 서로 다른 클래스와 연동되었으므로 ISP 법칙

기존 없었던 인터페이스가 생겨 클라이언트와 수행자 사이에서 둘을 연결시켜 주므로 OCP와 DIP에 해당됨

 

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

인터페이스를 클라이언트에 특화되도록 분리시키라는 것으로 범용의 공통적인 인터페이스를 여러 클래스가 공유해서 사용하지 말라는 것, 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
'하나의 인터페이스를 여러 클래스가 공유하지 말아라' 라는 원칙임

 

의존관계 역전 원칙(DIP, Dependency inversion principle)

추상화에 의존해야지, 구체화에 의존하면 안된다
의존 관계를 맺을 때 변하기 쉬운것 또는 자주 변하는 것 보다는 변화하기 어려운 것 또는 거의 변화가 없는 것에 의존해야 함
'무언가를 의존할 때, 구체 클래스에 의존하지 말고 인터페이스에 의존해라'라는 원칙

 


2016년 27번

정답 : 2번

Server를 AServer와 BServer가 상속하고 있음. 즉 Server는 기반 클래스이고 AServer와 BServer는 파생클래스임

 

ClassA는 파생클래스인 AServer와 BServer클래스를 의존하고 있음. 이것만 봐도 리스코프 치환 원칙을 위반하고 있음

리스코프 원칙에 따르면 기반 클래스는 파생클래스로 대체할 수 있어야 하는데, 문제에서 ClassA는 기반클래스가 아닌 파생클래스를 의존하고 있기 때문에 대체가 어려움

 

리스코프 치환 원칙을 지키려면 ClassA는 Server클래스를 의존해야 하며, AServer와 BServer의 의존은 없애야 함

 

리스코프 치환 원칙
(LSP, Liskov substitution principle)
'원래 하기로 정한 것을 바꾸지 말아라'
자식클래스는 최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야 함
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 서브타입(하위클래스)은 어디서나 자신의 기반타입(상위클래스) 인스턴스로 바꿀 수 있어야 함
부모 클래스에서 상속받은 메서드들이 자식 클래스에 오버라이드, 즉 재정의하지 않는 것

 


2017년 47번

정답 : 1번

원칙 위배 코드의 경우 클래스 내부에서 인스턴스타입에 따라 draw 기능을 수행하는 메소드 여부를 결정하고 있음 인스턴스 유형이 추가되거나 변경 될 경우 코드도 함께 변경되어야 하므로 개방/폐쇄 원칙을 위배됨.

원칙을 준수한 코드의 경우 별도의 list 자료구조(배열)을 통해 draw메소드 실행을 제어함

 

클라이언트는 draw함수만 호출하면 됨. 사각형이든, 원이든, 삼각형이든 상관 없이 draw함수만 호출하면 클래스가 알아서 해줌

개방 폐쇄 원칙
(OCP, Open/closed principle)
소프트웨어 요소는 확장에는 열려있으나 변경에는 닫혀 있어야 함
변하는 것과 변하지 않는 것을 구분한 후, 변해야 하는 것은 쉽게 변할 수 있게하고 변하지 않아야 할 것은 변하는 것에 영향을 받지 않게 하는 것
클래스를 변경하지 않고도 대상 클래스의 환경을 변경할 수 있는 설계가 되어야 함
특히 단위 테스트를 수행할 때 매우 중요함