본문 바로가기
기초 CS 정리

함수형 프로그래밍과 객체지향 프로그래밍

by 쿠리의일상 2023. 2. 3.

함수형 프로그래밍

💡 순수 함수를 조합하고 공유 상태, 변경 가능한 데이터 및 부작용을 피해 소프트웨어를 만드는 프로세스

 

선언형 프로그래밍으로 애플리케이션의 상태는 순수 함수를 통해 전달된다.

애플리케이션의 상태가 일반적으로 공유되고 객체의 메서드와 함께 배치되는 OOP와 대조되는 프로그램 방식이다.

  • 명령형 프로그래밍(절차지향, 객체지향)
    • 상태와 상태를 변경시키는 관점에서 연산을 설명하는 방식 → 어떻게 할지 표현
    • 알고리즘을 명시하고 목표는 명시하지 않음
  • 선언형(함수형) 프로그래밍
    • How 보다는 What을 설명하는 방식 → 무엇을 할 건지 표현
    • 알고리즘을 명시하지 않고 목표만 명시

 

함수형 코드는 명령형 프로그래밍이나 OOP코드보다 더 간결하고 예측가능하여 테스트가 쉽다.

함수형 프로그래밍은 프로그래밍 언어나 방식을 배우는 것이 아닌 함수로 프로그래밍하는 사고를 배우는 것으로 기존의 사고방식을 전환하여 프로그래밍을 더 유연하게 문제해결 하도록 접근하는 방식이다.

 

  • 순수 함수
    • 입출력이 순수해야 한다
    • 반드시 하나 이상의 인자를 받고, 받은 인자를 처리하여 반드시 결과물을 돌려줘야 한다.
    var arr = [1, 2, 3, 4, 5];
    var map = arr.map (function(x) {
    	return x * 2;
    });
    /*
    	arr를 넣어서 map이라는 새로운 배열을 얻었다. 
    	원본 데이터arr에 값은 변하지 않았고 부작용도 나오지 않았음
    */
    
    • 순수함수로 만들면 에러를 추적하는 것이 쉬워진다 → 인자에 문제가 있거나 함수 내부에 문제가 있거나 둘 중 하나이므로.
  • 합성 함수
  • 공유 상태 피하기
  • 상태 변화 피하기
  • 부작용 피하기
    • 프로그래머가 바꾸고자 하는 변수 외에는 변경되면 안된다. 특히 원본 데이터는 절대 불변해야 한다.

대표적인 자바스크립트 함수형 프로그래밍 함수 : map, filter, reduce

 

 

객체지향 프로그래밍(OOP)

객체지향 패러다임 이전

  1. 순차적, 비구조적 프로그래밍
    • 말그대로 순차적으로 코딩해나가는 것으로 필요한 게 있으면 계속 순서대로 추가해가며 구현하는 방식
    • 직관적이나 규모가 커지게 되면
    • goto문을 활용
      • 만약 이전에 작성했던 코드가 다시 필요하면 그 곳으로 이동하기 위한 것으로 점점 규모가 커지면 goto문을 무분별하게 사용하게 되고 실뜨기를 하는 것처럼 꼬이게 된다.
      • 코딩보다 흐름을 이해하는데 시간을 낭비할 가능성이 크다.
  2. 절차적, 구조적 프로그래밍
    • 반복될 가능성이 있는 것들을 재사용이 가능한 함수(프로시저)로 만들어서 사용하는 프로그래밍 방식
    • 절차→함수(프로시저), 구조→모듈
    • 프로시저란 반환값이 따로 존재하지 않는 함수를 뜻한다. 예를 들어 printf같은 함수는 반환값을 얻기 위함보단 화면에 출력하는 용도로 쓰이는 함수임 (물론 int형을 리턴하기는 하지만 목적 자체는 프로시저에 가까움)
    • 너무 추상적인 것이 문제점
  3. 객체지향 프로그래밍
    • 클래스마다 필요한 필드를 선언하고 getter setter로 구성된 모습으로 해결
    • 특정한 개념의 함수와 자료형을 함께 묶어서 관리하기 위해 탄생
    • 객체 내부에 자료형(필드)와 함수(메서드)가 같이 존재한다는 점이 중요
    • 객체 간 독립성이 생기고 중복 코드의 양이 줄어드는 장점과 유지보수에 유리하다.

객체 지향의 4가지 특성

  1. 추상화 (Abstraction)
    • 필요로 하는 속성이나 행동을 추출하는 작업
    • 추상적인 개념에 의존하여 설계해야 유연함을 갖출 수 있다.
    • 세부적인 사물들의 공통적인 특징을 파악한 후 → 하나의 집합으로 만들어내는 것이 추상화
  2. 캡슐화 (Encapsulation)
    • 낮은 결합도를 유지하기 위한 설계
    • 한 곳에서 변화가 일어나도 다른 곳에 미치는 영향을 최소화시키는 것 (객체가 내부적으로 기능을 어떻게 구현하는지 감추는 것)
    • 결합도(coupling)란 어떤 기능을 실행할 때 다른 클래스나 모듈에 얼마나 의존적인가를 나타내는 단어로, 독립적으로 만들어진 객체들 간의 의존도가 최대한 낮게 만드는 것이 중요하다.
    • 객체 안의 모듈 간의 요소가 밀접한 관련이 있는 것으로 구성하여 응집도를 높이고 결합도를 줄여야 요구사항 변경에 대처가 용이해진다.
    • 외부에서 접근할 필요가 없는 것들은 private를 사용하여 정보 은닉을 해줘서 결합도를 낮춰준다.
  3. 상속
    • 일반화 관계(Generalization)
    • 여러 개체들이 지닌 공통된 특성을 부각시켜 하나의 개념이나 법칙으로 성립하는 과정
    • 자식 클래스를 외부로부터 은닉하는 캡슐화의 일종
    • 자식 클래스를 캡슐화해두면 외부에선 이러한 클래스들에 영향을 받지 않고 개발을 이어갈 수 있다.
    • IS-A 관계가 성립할 때와 재사용 관점이 아닌 기능의 확장 관점일 때 상속을 사용해준다.
    • 상속 재사용의 단점
      • 자식 클래스가 많을 때 상위 클래스(부모 클래스)의 변경이 어려워진다. → 부모 클래스가 변경되면 의존하는 자식 클래스들이 영향을 받게 된다.
      • 불필요한 클래스가 증가한다.
      • 상속이 잘못 사용될 수 있다.
        • 상속 받는 클래스가 부모 클래스와 IS-A 관계가 아닐 수 있다 → 객체 조립(Composition)으로 해결
        • 객체 조립이란 필드에서 다른 객체를 참조하는 방식으로 구현되며, 상속에 비해 비교적 런타임 구조가 복잡해지고 구현이 어려운 단점이 존재하지만 변경 시 유연함을 확보하는데 장점이 크다. 그러므로 같은 종류가 아닌 클래스를 상속하고 싶을 때는 객체 조립을 우선적으로 적용하는 것이 좋다.
  4. 다형성 (Polymorphism)
    • 서로 다른 클래스의 객체가 같은 메시지를 받았을 때 각자의 방식으로 동작하는 능력
    • 상속과 함께 활용
    • 부모 클래스의 메서드를 자식 클래스가 오버라이딩해서 자신의 역할에 맞게 활용하는 것
    • 다형성을 활용하면 구체적으로 현재 어떤 클래스 객체가 참조되는 지 무관하게 프로그래밍 하는 것이 가능

 

객체 지향 설계 과정

  1. 제공해야할 기능을 찾고 세분화
  2. 그 기능을 알맞은 객체에 할당
  3. 기능을 구현하는데 필요한 데이터 추가
  4. 데이터를 이용하는 기능 추가
  5. 기능은 최대한 캡슐화하여 구현
  6. 객체 간 어떻게 메서드 요청을 주고받을 지 결정

 

객체 지향 설계 원칙 (SOLID)

  1. SRP (Single Responsibility) : 단일 책임 원칙
    • 클래스는 한 개의 책임을 가져야한다
    • 클래스를 변경하는 이유는 한 개여야 한다.
    • 이를 지키지 않으면 한 책임의 변경에 의해 다른 책임과 관련된 코드에 영향이 갈 수 있다.
  2. OCP (Open-Closed) : 개방 폐쇄의 원칙
    • 확장에는 열려있어야 하고 변경에는 닫혀 있어야 한다.
    • 기능을 변경하거나 확장할 수 있으면서 그 기능을 사용하는 코드는 수정하지 않는다.
    • 이를 지키지 않으면 instanceof 와 같은 연산자를 사용하거나 다운 캐스팅이 일어난다.
  3. LSP (Liskov Substitutuon) : 리스코프 치환 원칙
    • 상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다.
    • 상속 관계가 아닌 클래스들을 상속 관계로 설정하면 이 원칙이 위배된다.
  4. ISP (Interface Segregation) : 인터페이스 분리 원칙
    • 인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다.
    • 각 클라이언트가 필요로 하는 인터페이스들을 불리함으로써 각 클라이언트가 사용하지 않는 인터페이스에 변경이 발생하더라도 영향을 받지 않도록 만들어야 한다.
  5. DIP (Dependency Inversion) : 의존 역전 원칙
    • 고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다.
    • 저수준 모듈은 고수준 모듈에서 정의한 추상 타입에 의존해야 한다.
    • 저수준 모듈이 변경돼도 고수준 모듈은 변경할 필요가 없다.

'기초 CS 정리' 카테고리의 다른 글

TCP 3way handshake  (0) 2023.02.05
OSI 7계층  (0) 2023.02.04
파일 시스템  (0) 2023.02.02
메모리 관리와 페이지 교체  (0) 2023.02.01
Race Condition  (0) 2023.01.31