Study/TIL(Today I Learned)

24.08.26 CS, C++

에린_1 2024. 8. 26. 18:51
728x90

24.0CS

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

  • ISP 원칙이란 범용적인 인터페이스 보다는 클라이언트(사용자)가 실제로 사용하는 Interface를 만들어야 한다는 의미로, 인터페이스를 사용에 맞게 끔 각기 분리해야 한다는 설계 원칙이라고 보면 된다.
  • 만약 인터페이스의 추상 메서드들을 범용적으로 이것저것 구현한다면, 그 인터페이스를 상속받은 클래스는 자신이 사용하지 않는 인터페이스마저 억지로 구현해야 하는 상황이 올 수도 있다. 또한 사용하지도 않는 인터페이스의 추상 메소드가 변경된다면 클래스에서도 수정이 필요하게 된다.
  • 즉, 인터페이스 분리 원칙이란 인터페이스를 잘게 분리함으로써, 클라이언트의 목적과 용도에 적합한 인터페이스 만을 제공하는 것이다.
  • 인터페이스 분리 원칙은 마치 단일 책임 원칙과 비슷하게 보이는데, SRP 원칙이 클래스의 단일 책임을 강조한다면, ISP는 인터페이스의 단일 책임을 강조한다고 말할 수 있다. 또한 SRP 원칙의 클래스 책임의 범위에 대해 분리 기준이 다르듯이, 인터페이스를 분리하는 기준은 상황에 따라 다르다. 핵심은 관련 있는 기능끼리 하나의 인터페이스에 모으되 지나치게 커지지 않도록 크기를 제한하라는 점이다.

ISP 원칙 적용 주의점

  • SRP와 ISP 원칙 사이의 관계
    • 책임을 잘 구성해놓아도 실제 적용되는 객체에겐 부합되지 않을 수 있기 떄문에 책임을 잘 분리해야 한다.
    • ISP는 SRP를 만족하면 성립되는가 라고 질문한다면 반드시 그렇다고는 볼 수 없다.
  • 인터페이스 분리는 한 번만
    • ISP 원칙의 주의해야 할 점은 한 번 인터페이스를 분리하여 구성해놓고 나중에 무언가 수정사항이 생겨서 또 인터페이스들을 분리하는 행위를 가하면 안된다.
    • 이미 구현되어 있는 프로젝트에 또 인터페이스들을 분리한다면, 이미 해당 인터페이스를 구현하고 있는 온갖 클래스들과 이를 사용하고 있는 클라이언트(사용자)에게 문제가 일어날 수 있기 때문이다.
    • 인터페이스라는 건 한 번 구성하였으면 왠만해선 변경하면 안되는 정책같은 개념이다. 따라서 처음 설계부터 기능의 변화를 생각해두고 인터페이스를 설계해야 한다.

참조

https://inpa.tistory.com/entry/OOP-💠-아주-쉽게-이해하는-ISP-인터페이스-분리-원칙

DIP(의존 역전 원칙)

  • DIP 원칙이란 객체에서 어떤 Class를 참조해서 사용해야 하는 상황이 생긴다면, 그 Class를 직접 참조하는 것이 아니라 그 대상의 상위 요소(추상 클래스 or 인터페이스)로 참조하라는 원칙이다.
  • 객체들이 서로 정보를 주고 받을 때는 의존 관계가 형성되는데, 이 때 객체들은 나름대로의 원칙을 갖고 정보를 주고 받아야하는 약속이 있다. 여기서 나름대로의 원칙이란 추상성이 낮은 클래스보다 추상성이 높은 클래스와 통신을 한다는 의미이다.
    • 클래스 간 의존 관계란, 한 클래스가 어떤 기능을 수행하려고 할 때, 다른 클래스의 서비스가 필요한 경우를 말한다.
  • 다시 말하면 클라이언트(사용자)가 상속 관계로 이루어진 모듈을 가져다 사용할때, 하위 모듈을 직접 인스턴스를 가져다 쓰지말라는 뜻이다. 왜냐하면 그렇게 할 경우, 하위 모듈의 구체적인 내용에 클라이언트가 의존하게 되어 하위 모듈에 변화가 있을 때마다 클라이언트나 상위 모듈의 코드를 자주 수정해야 되기 때문이다.
  • 따라서 한마디로 상위의 인터페이스 타입의 객체로 통신하라는 원칙이다.

참조

https://inpa.tistory.com/entry/OOP-💠-아주-쉽게-이해하는-DIP-의존-역전-원칙

C++

참조자

  • C언어에서는 어떠한 변수를 가리키고 싶을 때 반드시 포인트를 사용해야 했다. C++에서는 다른 변수나 상수를 가리키는 방법으로 또 다른 방식을 제공하는데, 이를 바로 참조자(레퍼런스 - reference)라고 부른다.
  • 참조자를 정하는 방법은 가리키고자 하는 타입 뒤에 &를 붙이면 된다. 위처럼 int 형 변수의 참조자를 만들고 싶을 때는 int& , double 의 참조자를 만드려면 double& 로 하면 된다. 심지어 int* 와 같은 포인터 타입의 참조자를 만드려면 int*&로 쓰면 된다.
  • 참조자 선언은 또 다른 이름 이라고 컴파일러에게 알려주는 것이다. 따라서 참조자는 어떠한 작업을 수행하든 참조된 원본에 그 작업을 하는 것과 마찬가지이다.
  • 참조자는 포인터와 상당히 유사한 개념이지만 몇 가지 차이점이 있다.
    1. 레퍼런스는 반드시 처음에 누구의 별명이 될 것인지 지정해야 한다 따라서 아래와 같은 문장은 불가능하다. 반면 포인터의 경우 전혀 문제가 없는 코드이다.
    2. int& another_a; // X int* p; // O
    3. 레퍼런스가 한 번 별명이 되면 절대 다른 이의 별명이 될 수 없다.
      • 한 번 어떤 변수의 참조자가 되버린다면, 더 이상 다른 변수를 참조 할 수 없게 된다.
    4. 레퍼런스는 메모리 상에 존재하지 않을 수도 있다.
      • 이의 경우 another_a 가 쓰이는 자리는 모두 a 로 바꿔치기 하면 되기 때문에 레퍼런스가 메모리 상에 존재하지 않게 된다.
    5. int a = 10; int &another_a = a;

상수에 대한 참조자

  • 상수 값 자체는 리터럴 이기 떄문에 많일 위와 같이 레퍼런스로 참조한다면 리터럴의 값을 바꾸는 말도 안되는 행위가 가능하기 때문에 따라서 C++ 문법 상 상수 리터럴을 일반적인 레퍼런스가 참조하는 것은 불가능하게 되어 있다.
  • 물론 그 대신에
  • const int &ref = 4;
  • 상수 참조자로 선언한다면 리터럴도 참조할 수 있다.

레퍼런스의 배열과 배열의 레퍼런스

  • 컴파일에서 레퍼런스의 배열을 불법(illegal)이라고 한다. C++ 규정에서 언어 차원에서 불가능하다고 나와 있다.
  • C++ 상에서 배열이 어떻게 처리되는 지 생각해본다면, 문법 상 배열의 이름은 (arr ) 첫 번째 원소의 주소값으로 변환이 될 수 있어야 한다. 이 때문에 arr[1] 과 같은 문장이 *(arr + 1) 로 바뀌어서 처리될 수 있다.
  • 주소값이 존재한다라는 의미는 해당 원소가 메모리 상에서 존재한다 라는 의미와 같다. 하지만 레퍼런스는 특별한 경우가 아닌 이상 메모리 상에서 공간을 차지하지 않는다. 따라서 이러한 모순 때문에 레퍼런스들의 배열을 정의하는 것은 언어 차원에서 금지가 되어 있다.
  • 그와 반대인 배열들의 레퍼런스가 불가능 한 것은 아니다.

레퍼런스를 리턴하는 함수

  • 지역변수의 레퍼런스를 리턴해서 컴파일 한다면 경고가 나오고 실제로 실행해보면 런타임 오류가 발생한다.
  • 이와 같이 레퍼런스는 있는데 원래 참조 하던 것이 사라진 레퍼런스를 댕글링 레퍼런스(Dangling reference)라고 부른다.
    • 따라서 레퍼런스를 리턴하는 함수에서 지역 변수의 레퍼런스를 리턴하지 않도록 조심해야 한다.
  • 참조자를 리턴하는 경우 C언어에서 엄청나게 큰 구조체가 있을 때 해당 구조체 변수를 그냥 리턴하면 전체 복사가 발생해야 해서 시간이 오래 걸리지만, 해당 구조체를 가리키는 포인터를 리턴한다면 그냥 포인터 주소 한 번 복사로 매우 빠르게 끝난다. 마찬가지로 레퍼런스를 리턴하게 된다면 레퍼런스가 참조하는 타입의 크기와 상관 없이 딱 한 번의 주소값 복사로 전달이 끝나게 된다.

참조자가 아닌 값을 리턴하는 함수를 참조자로 받기

  • 원칙상 함수의 리턴 값은 해당 문장이 끝나면 소멸되는 것이 정상이다. 하지만 예외적으로 상수 레퍼런스로 리턴값을 받게 되면 해당 리턴 값의 생명이 연장된다. 그리고 그 연장되는 기간은 레퍼런스가 사라질 때 까지이다.

함수에서 값 리턴(int f()) 함수에서 참조자 리턴(int& f())

값 타입으로 받음( int a = f() ) 값 복사됨 값 복사됨. 다만 지역 변수의 레퍼런스를 리턴하지 않도록 주의
참조자 타입으로 받음( int & a = f() ) 컴파일 오류 가능. 다만 지역 변수의 레퍼런스를 리턴하지 않도록 주의
상수 참조자 타입으로 받음 ( const int& a = f() ) 가능 가능. 다만 지역 변수의 레퍼런스를 리턴하지 않도록 주의
728x90

'Study > TIL(Today I Learned)' 카테고리의 다른 글

24.08.29 CS, C++  (0) 2024.08.29
24.08.27 CS, C++  (0) 2024.08.27
24.08.23 CS  (0) 2024.08.23
24.08.22 CS, C++  (0) 2024.08.22
24.08.21 CS  (0) 2024.08.21