개발자 블로그

OOP(SOLID)와 FP 본문

CS/패러다임

OOP(SOLID)와 FP

hayongwoon 2022. 6. 10. 10:23

 시작하기에 앞서 객체지향 프로그래밍과 함수형 프로그래밍은 반대되는 개념이 아닌 상호 보완적 개념이라고 할 수 있다. 둘의 특징과 예시를 통해 무엇이 다른지 알아보며, 어떻게 적용하며 프로그래밍할지가 해당 주제의 핵심일 것 같다.

1. OOP

객체지향의 특성

  • 다형성 : 오버로딩과 오버라이딩을 통해 기능(메소드)를 여러가지의 형태로 상황과 개발자의 선택에 따라 그 동작(형태)이 달라질 수 있음.
  • 추상화 : 다수의 객체의 공통된 부분만을 추려내는 것, 복잡한 문제를 간단한(핵심적인) 형태로 구현해보는 것 
  • 캡슐화 : 객체의 메소드와 속성을 하나로 묶어 관리하는 방법이며, 정보 은닉(보호)과 재활용성 등의 목적이기도 하다. 
  • 상속성 : 부모 클래스(상위)의 특성을 토대로 자식(하위) 클래스를 생성하며 확장성과 유지보수 등을 하기 위함

*단어 정리

- 오버로딩 : 같은 이름을 가진 메소드를 여러가지 두는 것을 말한다. '정적' 다형성이라고도 말한다.

- 오버라이딩 : 상속을 통해 부모의 메소드를 따로 선언하지 않아도 사용할 수 있지만, 다르게 사용하고 싶을 때, 새롭게 정의하는 것을 의미 

 

위의 특징들을 기반으로 객체지향 프로그래밍을 SOLID라고 정리할 수 있다!

 

SOLID

Single Responsibility Principle : 객체는 오로지 하나의 책임만을 갖는다.

 만약 하나의 객체 안에 여러가지 프로세스가(기능) 있으면 해당 객체를 갖고 재활용하고 확장하기 편할까를 생각해보자! 다른 객체에서 해당 객체의 일부 기능과 같은 기능을 사용할 때 코드가 중복될 수도 있다는 것이다. 때문에 객체는 오로지 하나의 기능만을 가져야한다.

 

Open Closed Principle : 변경에는 닫혀있고, 확장에는 열려있다. 

 캡슐화를 통해 메소드와 속성을 하나로 묶어 관리를 하는데, 속성(정보)를 쉽게 변경할 수 있다면 우리는 의도치 않은 결과값을 받을 수도 있겠다. 따라서 게터와 세터와 같은 메소드로 정보에 접근하도록 정보은닉을 하기도 한다. 이렇게 객체를 수정하는 것은 지양하고 확장을 하는 것을 지향해야한다는 것! 즉, 객체를 단순화하여 이를 클라이언트의 요구에 맞게 업그레이드(확장)한 버전(객체)들을 생성해야한다!

 

Liskov Substitution Principle : 상위 타입을 하위 타입으로 교체하더라도 정상 작동해야한다. 

객체의 정확성을 떨어뜨리지 않으면서도 부모 클래스에 자식 클래스를 넣어도 문제가 없어야한다. 왜냐면 상속을 받아 해당 객체의 기능을 갖고있고 추가로 무언가를 더 확장한 것이기 때문이다. 하지만 만약 자식 클래스에서 부모에게 받은 어떠한 메소드를 오버라이딩을 했다면, 완전히 대체할 수 없으므로 이러한 부분을 주의해야한다.

 

Interface Segregation Principle : 하나의 일반적인 인터페이스 보다는 구체적인 여러 개의 인터페이스를 구성해야한다.

클라이언트 입장에서 필요한 기능 중심으로 인터페이스를 구체적으로 분리, 모듈화해야한다는 것이다.

 

Dependency Inversion Principle : 상위 계층는 하위 계층의 변화로 부터 독립적이여야한다.

때문에 상위 계층은 하위 계층보다 추상적이여야한다. 예를 들어 타이어를 만드는 틀이 있다고 하면 아주 기본적인 틀(부모)을 만들어 놔야 이를 통해 소비자의 요구에 맞는 다양한 타이어틀로 변경을 할 수 있다는 것이다. 

 

 

2. FP

FP란?

선언형 프로그래밍의 일종으로 함수형 프로그래밍은 작은 '순수 함수'들을 블록들을 쌓아 로직을 구현하고 '고차 함수'를 통해 함수의 재활용성을 높인 프로그래밍 패러다임이다. 아무래도 함수를 작은 단위로 모듈화 했기 때문에! 여러가지 장점들이 파생되어 나오는 것 같다. 

 

순수 함수

 변수의 불변성을 지키며, 항상 동일한 인풋값에는 동일한 결과값이 나와야한다.

 

고차 함수

 순수 함수를 통해 만들어진 함수로 함수를 하나의 값으로 다음 이어지는 함수의 매개변수로 받아(커링) 로직을 이어나갈 수 있는 함수이다. 

 

일급 객체

고차 함수를 사용하기 위해서는 해당하는 언어가 일급 객체라는 특징이 있어야한다고 한다.

  • 변수나 메서드에 함수를 할당할 수 있다.
  • 함수 안에는 함수를 매개변수로 담을 수 있다.
  • 함수가 함수를 반환할 수 있다.

일급객체의 특징을 보면서 파이썬에서도 람다라던지 함수도 객체인 특징을 살려 꽤 함수형 언어의 특징을 잘 보여줄 수 있는 것 같다. 물론 변수의 불변성은 뮤터블한 리스트나 딕셔너리와 같은 객체는 해당하지 않지만 고차함수를 만드는 과정 그리고 일급객체의 특징을 잘 살릴 수 있을것 같다. 특히 이러한 부분들은 race condition 스레드의 자원을 공유하면서 생기는 문제들을 막아줄 수 있고, 병렬 처리에 장점을 가질 수 있을 것 같다. 

 

정리하자면...함수형 프로그래밍은!

  • 프로그래밍 패러다임 중 하나
  • 순수 함수를 통해 로직의 흐름이 생긴다.
  • 병렬 처리에 장점을 갖는다.
  • 간결하고 재사용성이 높다.