IT/Front-End

[리팩토링 2판] 11장 API 리팩터링 - 일급 함수와 명령 객체

KimCookieYa 2024. 12. 1. 17:32

함수를 명령으로 바꾸기(Replace Function with Command)

함수를 그 함수만을 위한 객체 안으로 캡슐화하는 것 => 이를 명령(Command) 객체라고 한다.

일급 함수(first-class function)을 지원하지 않는 프로그래밍 언어에서 "명령 객체"를 사용해서 일급 함수의 기능 대부분을 흉내 낼 수 있다.

위의 문장이 바로 이해되지는 않았다. "일급 함수"도 여러번 들었는데 들을 때마다 까먹기도 하고.. 그래서 지피티에게 물어봤다.

 

일급 함수(First-Class Function)란, 프로그래밍 언어에서 함수가 다른 일반 데이터 타입(예: 숫자, 문자열)처럼 취급될 수 있음을 의미합니다. 즉, 함수가 변수에 할당되거나, 다른 함수의 인자로 전달되거나, 반환값으로 사용할 수 있다는 특징을 가지는 것을 말합니다.
일급 함수의 특징: 변수에 할당 가능함수 자체를 변수에 저장할 수 있습니다.함수의 인자로 전달 가능다른 함수의 매개변수로 함수를 전달할 수 있습니다.함수의 반환값으로 사용 가능함수를 호출한 결과로 또 다른 함수를 반환할 수 있습니다.

 

그러니까 내가 평소에 함수에 이벤트 핸들러를 넘겨주거나 콜백 함수를 넘겨주는 행위가 JavaScript에서 일급 함수 기능을 지원했기 때문에 가능했다는 거구나.

 

#include <stdio.h>

// 두 숫자를 더하는 함수
int add(int a, int b) {
    return a + b;
}

// 두 숫자를 곱하는 함수
int multiply(int a, int b) {
    return a * b;
}

// 함수를 포인터로 받아 실행
int executeOperation(int (*operation)(int, int), int a, int b) {
    return operation(a, b);
}

int main() {
    printf("%d\n", executeOperation(add, 2, 3));      // 5
    printf("%d\n", executeOperation(multiply, 2, 3)); // 6
    return 0;
}

 

C언어는 일급 함수를 지원하지 않지만, 함수 포인터를 통해 일급 함수와 유사한 기능을 할 수 있다고는 한다. 그러니까 함수 포인터와 함수 자체를 별개의 개념으로 봐야하는 거구나. 그리고 C언어에서는 함수 반환은 불가능하다.

 

 

그런데 "명령 객체"를 사용하면 일급 함수의 기능을 흉내낼 수 있다던데 이게 어떻게 가능한지 모르겠어서 또 지피티에게 물어봤다.

 

JavaScript에서 일급 함수 예제

function add(a, b) {
  return a + b;
}

function multiply(a, b) {
  return a * b;
}

function executeOperation(operation, a, b) {
  return operation(a, b);
}

console.log(executeOperation(add, 2, 3)); // 5
console.log(executeOperation(multiply, 2, 3)); // 6

 

C++에서 명령 객체 예제

#include <iostream>
#include <memory>
#include <vector>

// 명령 객체의 인터페이스
class Command {
public:
    virtual int execute(int a, int b) = 0;
    virtual ~Command() = default;
};

// 더하기 명령
class AddCommand : public Command {
public:
    int execute(int a, int b) override {
        return a + b;
    }
};

// 곱하기 명령
class MultiplyCommand : public Command {
public:
    int execute(int a, int b) override {
        return a * b;
    }
};

// 명령 실행 함수
int executeOperation(Command* command, int a, int b) {
    return command->execute(a, b);
}

int main() {
    // 명령 객체 생성
    AddCommand add;
    MultiplyCommand multiply;

    // 명령 실행
    std::cout << "Add: " << executeOperation(&add, 2, 3) << std::endl;      // 5
    std::cout << "Multiply: " << executeOperation(&multiply, 2, 3) << std::endl; // 6

    return 0;
}

 

C++에서는 익명 함수를 쓸 수 없기 때문에 명령 객체를 생성한 후 넘겨주는 과정이 영 탐탁치 않긴 하지만, 그래도 명령 객체를 통해 일급 함수와 유사한 코딩이 가능해졌다. 확실히 일급 함수를 지원하는 JavaScript가 간결하고 직관적인 코딩이 수월한 것 같다.

 

일급 함수를 지원하는 JS에서는 명령 객체를 쓸 일이 적을 것 같긴한데, 비슷한 유틸 함수들을 하나의 명령 객체로 묶어서 모듈로 관리하면 편리할 것 같다는 생각이 들었다.