잡동사니

ChatGPT의 활용 (feat. 동적 바인딩 with Java) 본문

IT/AI

ChatGPT의 활용 (feat. 동적 바인딩 with Java)

yeTi 2023. 5. 12. 17:39

안녕하세요. yeTi입니다.
ChatGPT의 활용법 (feat. 정보수집 방식의 전환) 에서 ChatGPT의 쓰임새를 인식하고 ChatGPT를 활용하여 궁금증을 해소한 예시를 공유하고자 합니다.
더하여 Microsoft에서 개발한 Bing AI와 비교하여 답변의 차이를 확인하고자 합니다.

문답

프로그래밍 언어의 동적 바인딩 개념에 대해 알아?

예, AI 언어 모델로서 프로그래밍 언어의 동적 바인딩 개념에 대해 잘 알고 있습니다.

동적 바인딩은 런타임에 실행할 메서드나 함수의 결정을 프로그램의 실제 런타임까지 연기하는 객체 지향 프로그래밍에서 사용되는 기법입니다. 이는 컴파일 타임에 실행할 메서드나 함수가 결정되는 정적 바인딩과 대조적입니다.

동적 바인딩에서는 실행할 메서드에 대한 결정이 객체를 참조하는 데 사용되는 참조 변수의 유형이 아니라 런타임에 객체의 실제 유형에 따라 결정됩니다. 따라서 기존 코드를 변경하지 않고도 새로운 서브클래스를 추가할 수 있으므로 객체 지향 프로그램에서 유연성과 확장성을 높일 수 있습니다.

동적 바인딩은 Java, Python, C++ 등 많은 객체 지향 프로그래밍 언어에서 구현됩니다. 예를 들어 Java에서 동적 바인딩은 서브클래스에 의해 재정의될 수 있는 메서드인 가상 메서드를 사용하여 구현됩니다.

말한것 처럼 Java에서 동적 바인딩을 구현하는 방법은 추상 클래스를 사용하는 것인데, 이것이 인터페이스나 상속을 사용하는 것과 어떻게 다를까?

Java에서 동적 바인딩은 상속뿐만 아니라 추상 클래스와 인터페이스를 모두 사용하여 달성할 수 있습니다. 그러나 각 접근 방식의 메커니즘과 의미는 약간 다릅니다.

추상 클래스는 여러 하위 클래스 간에 공유할 수 있는 공통 구조 또는 동작을 정의하는 데 사용됩니다. 추상 메서드와 구체적인 메서드를 모두 포함할 수 있으며, 구체적인 메서드는 필요한 경우 하위 클래스에서 재정의할 수 있는 기본 구현을 제공합니다. 추상 메서드를 정의함으로써 추상 클래스는 서브클래스와 계약을 체결하여 특정 기능을 제공하도록 보장할 수 있습니다. 추상 클래스는 추상 메서드와 구체적인 메서드를 모두 가질 수 있기 때문에 서브클래스 간에 공유 동작과 특수 동작을 혼합하여 표현하는 데 사용할 수 있습니다.

반면 인터페이스는 인터페이스를 구현하는 모든 클래스에서 구현해야 하는 메서드 집합을 정의하는 데 사용됩니다. 인터페이스에는 구체적인 메서드 구현이 포함되지 않고 메서드 서명만 포함됩니다. 인터페이스를 정의하면 구현 클래스가 준수해야 하는 계약을 지정하여 특정 기능을 제공하도록 보장할 수 있습니다. 인터페이스는 구체적인 메서드 구현을 포함하지 않기 때문에 클래스 간에 공유되는 동작의 순수한 집합을 나타내는 데 사용할 수 있습니다.

한편 상속은 하위 클래스가 부모 클래스의 동작을 상속할 수 있는 메커니즘입니다. 상속을 사용하면 하위 클래스가 부모 클래스의 코드를 재사용할 수 있으며 클래스 간의 "is-a" 관계를 모델링하는 데 사용할 수 있습니다. 클래스를 확장하면 하위 클래스는 부모 클래스의 모든 메서드와 필드뿐만 아니라 부모 클래스가 구현하는 모든 인터페이스에 액세스할 수 있습니다.

따라서 추상 클래스와 인터페이스는 모두 Java에서 동적 바인딩을 달성하는 데 사용할 수 있지만, 서로 다른 특성을 가지며 약간 다른 용도로 사용됩니다. 추상 클래스는 하위 클래스 간의 공유 및 특수 동작을 혼합하여 정의하는 데 사용되는 반면, 인터페이스는 순수한 공유 동작 집합을 정의하는 데 사용됩니다. 상속은 클래스 간의 "is-a" 관계를 모델링하고 하위 클래스가 부모 클래스의 코드를 재사용할 수 있도록 하는 데 사용됩니다.

추상 클래스를 사용하여 하위 클래스 간의 공유 동작과 특수 동작을 혼합하여 정의하고 인터페이스를 사용하여 순수한 공유 동작 집합을 정의하는 Java 코드 예제를 보여줄 수 있어?

추상 클래스와 인터페이스 사용의 차이점을 보여주는 예제가 있습니다:

// Example using an abstract class to define shared and specialized behavior
abstract class Animal {
    // Shared behavior
    public void eat() {
        System.out.println("The animal is eating.");
    }

    // Specialized behavior
    public abstract void makeSound();
}

class Dog extends Animal {
    public void makeSound() {
        System.out.println("Woof!");
    }
}

class Cat extends Animal {
    public void makeSound() {
        System.out.println("Meow!");
    }
}

// Example using an interface to define shared behavior
interface Movable {
    void move();
}

class Car implements Movable {
    public void move() {
        System.out.println("The car is moving.");
    }
}

class Bicycle implements Movable {
    public void move() {
        System.out.println("The bicycle is moving.");
    }
}

이 예제에서 Animal 추상 클래스는 모든 동물이 갖는 공유 동작(eat() 메서드)과 각 서브 클래스에서 구현해야 하는 특수 동작(makeSound() 메서드)을 정의합니다. DogCat 클래스는 Animal 추상 클래스를 확장하여 개와 고양이에 특화된 특수 동작인 makeSound() 메서드를 자체적으로 구현하여 제공합니다.

반면에 Movable 인터페이스는 움직일 수 있는 모든 객체가 가져야 하는 순수한 공유 동작 집합(move() 메서드)을 정의합니다. CarBicycle 클래스는 Movable 인터페이스를 구현하고 이동할 수 있는 모든 객체에 적용되는 공유 동작인 move() 메서드에 대한 자체 구현을 제공합니다.

명확하게 설명해 줘서 고마워. 코드와 함께 보니 이해가 잘되네

천만에요! 코드 예제가 Java에서 추상 클래스와 인터페이스를 사용하는 것의 차이점을 명확히 하는 데 도움이 되셨다니 다행입니다. 더 궁금한 점이 있거나 더 많은 예제가 필요하시면 언제든지 문의해 주세요!

동적 바인딩에 대해 더 자세히 알고 싶은데, 읽어볼 만한 자료를 추천해 줄 수 있어?

프로그래밍 언어의 동적 바인딩에 대해 자세히 알아보는 데 도움이 될 만한 몇 가지 리소스를 소개합니다:

  1. 오라클 자바 튜토리얼: 다형성: 이 튜토리얼에서는 동적 바인딩을 포함한 Java의 다형성에 대한 기본 사항을 다룹니다.

  2. GeeksforGeeks: Java의 동적 메서드 디스패치 또는 런타임 다형성: 이 문서에서는 Java에서 동적 바인딩을 달성하는 데 사용되는 기술인 동적 메서드 디스패치에 대해 자세히 설명합니다.

  3. 스택 오버플로: Java에서 동적 바인딩과 다형성의 차이점은 무엇인가요? 이 스택 오버플로 스레드에서는 동적 바인딩과 다형성의 차이점과 그 연관성에 대해 명확하게 설명합니다.

  4. YouTube: Java의 동적 바인딩: 이 동영상에서는 Java의 동적 바인딩에 대한 소개와 함께 예제를 제공합니다.

  5. Medium: Java의 동적 바인딩 및 다형성: 이 문서에서는 코드 예제와 함께 Java의 동적 바인딩 및 다형성에 대한 심층적인 설명을 제공합니다.

이 리소스가 동적 바인딩에 대해 자세히 알아보는 데 도움이 되셨기를 바랍니다. 더 궁금한 점이 있으면 언제든지 문의해 주세요.

접근할 수 있는 URL 주소를 알려 주면 좋겠어

물론이죠! 제가 언급한 리소스에 대한 링크는 다음과 같습니다:

  1. 오라클 자바 튜토리얼: 다형성: https://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html

  2. GeeksforGeeks: Java의 동적 메서드 디스패치 또는 런타임 다형성: https://www.geeksforgeeks.org/dynamic-method-dispatch-runtime-polymorphism-java/

  3. 스택 오버플로: Java에서 동적 바인딩과 다형성의 차이점은 무엇인가요? https://stackoverflow.com/questions/2781293/what-is-the-difference-between-dynamic-binding-and-polymorphism-in-java

  4. YouTube: Java의 동적 바인딩: https://www.youtube.com/watch?v=fu4f4z-wJ4A

  5. Medium: Java의 동적 바인딩 및 다형성: https://medium.com/edureka/dynamic-binding-and-polymorphism-in-java-4f9c4602fb1f

도움이 되셨기를 바랍니다!

Spring 프레임워크는 프레임워크에서 빈을 생성하기 위해 DI를 지원하는데 인터페이스에 동적 바인딩을 사용하려면 어떻게 해야돼?

Spring에서는 인터페이스를 유형으로 사용하여 빈을 정의한 다음 런타임에 해당 인터페이스의 구현을 주입하여 인터페이스와 동적 바인딩을 사용할 수 있습니다. 이는 일반적으로 Spring의 종속성 주입(DI) 메커니즘을 사용하여 수행되며, 이를 통해 애플리케이션의 여러 구성 요소 간에 종속성을 정의할 수 있습니다.

다음은 예제입니다:

메서드 send(String message)를 정의하는 인터페이스 MessageService가 있다고 가정해 보겠습니다:

public interface MessageService {
    void send(String message);
}

이 인터페이스의 구현은 EmailService라고도 합니다:

@Service
public class EmailService 구현 MessageService {
    public void send(String message) {
        // 이메일을 보내는 코드
    }
}

이 인터페이스에 동적 바인딩을 사용하려면 MessageService 유형의 빈을 정의하고 런타임에 이 인터페이스의 구현을 삽입하면 됩니다:

@Configuration
public class AppConfig {
    @Bean
    public MessageService messageService() {
        return new EmailService(); // EmailService 구현 주입
    }
}

이제 MessageService를 사용해야 할 때 클래스에 간단히 삽입하면 됩니다:

@Service
public class MyService {
    private final MessageService messageService;

    @Autowired
    public MyService(MessageService messageService) {
        이.메시지서비스 = 메시지서비스;
    }

    public void sendMessage(String message) {
        messageService.send(message);
    }
}

이 예제에서 MyService 클래스는 MessageService 인터페이스에 의존하지만 해당 인터페이스의 특정 구현에는 신경 쓰지 않습니다. 런타임에 Spring은 AppConfig 클래스에 정의된 MessageService의 구현이기 때문에 EmailService의 인스턴스를 MyService에 주입합니다.

이러한 방식으로 인터페이스와 동적 바인딩을 사용하면 보다 모듈적이고 유연한 코드를 작성할 수 있으므로 애플리케이션의 나머지 부분에 영향을 주지 않고 특정 구성 요소의 구현을 쉽게 변경할 수 있습니다.

이메일 서비스 외에 Sms 서비스를 추가하려면 어떻게 확장해?

이메일 서비스 구현 외에 Sms 서비스 구현을 추가하려면 이메일 서비스 클래스가 메시지 서비스 인터페이스를 구현하는 방식과 유사하게 메시지 서비스 인터페이스를 구현하는 새 클래스를 만들면 됩니다:

@Service
public class SmsService implements MessageService {
    public void send(String message) {
        // SMS를 전송하는 코드
    }
}

이메일 서비스Sms 서비스 구현을 모두 사용하려면 AppConfig 클래스를 수정하여 두 개의 빈을 정의하면 됩니다:

@Configuration
public class AppConfig {
    @Bean
    public MessageService emailService() {
        return new EmailService();
    }

    @Bean
    public MessageService smsService() {
        return new SmsService();
    }
}

이제 MessageService 인터페이스의 EmailServiceSmsService 구현을 모두 클래스에 삽입할 수 있습니다:

@Service
public class MyService {
    private final MessageService emailService;
    비공개 최종 MessageService smsService;

    @Autowired
    public MyService(@Qualifier("emailService") MessageService emailService,
                     @Qualifier("smsService") MessageService smsService) {
        이 이메일 서비스 = 이메일 서비스;
        이.sms서비스 = sms서비스;
    }

    public void sendEmail(String message) {
        emailService.send(message);
    }

    public void sendSms(String message) {
        smsService.send(message);
    }
}

이 예제에서는 MessageService 유형의 두 개의 빈, 즉 emailServicesmsService를 정의했습니다. MyService의 생성자에서 @Qualifier 어노테이션을 사용하면 각 매개변수에 대해 어떤 구현을 주입할지 Spring에 알릴 수 있습니다.

이제 MyService 클래스에서 MessageService 인터페이스의 EmailServiceSmsService 구현을 모두 사용할 수 있으며, AppConfig 클래스에서 구성을 변경하여 필요에 따라 둘 사이를 전환할 수 있습니다.

MyService에서 이메일서비스와 sms서비스를 별도의 인스턴스 두 개가 아닌 단일 인스턴스로 관리할 수 있어?

예, MessageService 인터페이스를 구현하고 send() 메서드를 EmailServiceSmsService 인스턴스 모두에 위임하는 새 클래스를 생성하여 EmailServiceSmsService 인스턴스를 단일 인스턴스로 관리할 수 있습니다.

다음은 예제입니다:

@Service
public class CombinedMessageService implements MessageService {
    private final MessageService emailService;
    private final MessageService smsService;

    @Autowired
    public CombinedMessageService(@Qualifier("emailService") MessageService emailService,
                                   @Qualifier("smsService") MessageService smsService) {
        this.emailService = emailService;
        이.smsService = smsService;
    }

    public void send(String message) {
        emailService.send(message);
        smsService.send(message);
    }
}

이 예제에서는 MessageService 인터페이스를 구현하는 CombinedMessageService라는 새 클래스를 만들었습니다. 이 클래스에는 두 개의 생성자 매개변수가 있는데, 하나는 EmailService 유형이고 다른 하나는 SmsService 유형이며, 스프링에서 @Qualifier 어노테이션을 사용하여 주입합니다.

CombinedMessageServicesend() 메서드는 단순히 EmailServiceSmsService 인스턴스 모두에 send() 메서드를 위임합니다.

이제 메시지를 보내야 하는 곳이면 어디든 CombinedMessageService를 삽입할 수 있으며, 이 메서드는 EmailServiceSmsService 인스턴스 모두에 메시지를 전송합니다:

@Service
public class MyService {
    private final MessageService combinedMessageService;

    @Autowired
    public MyService(CombinedMessageService combinedMessageService) {
        this.combinedMessageService = combinedMessageService;
    }

    public void sendMessage(String message) {
        combinedMessageService.send(message);
    }
}

이 예제에서는 CombinedMessageServiceMyService 클래스에 삽입했습니다. 내 서비스sendMessage()메서드를 호출하면CombinedMessageService를 통해이메일서비스Sms서비스인스턴스 모두에send()` 메서드를 위임하게 됩니다.

Bing AI와 비교 (대화 스타일: 균형 잡힘)

프로그래밍 언어의 동적 바인딩 개념에 대해 알아?

예, 프로그래밍 언어의 동적 바인딩 개념에 대해 잘 알고 있습니다. 동적 바인딩은 프로그래밍 언어에서 사용되는 기술로, 컴파일 타임이 아닌 런타임에 함수 호출을 정의에 바인딩할 수 있습니다. 즉, 함수 호출이 호출되는 객체의 유형에 따라 런타임에 함수 호출이 해결됩니다. 이는 지연 바인딩 또는 런타임 다형성이라고도 합니다12.

동적 바인딩은 C++, Java, Python, Ruby, Perl과 같은 많은 프로그래밍 언어에서 사용됩니다1. 코드의 유연성과 확장성을 높여주는 객체 지향 프로그래밍에 특히 유용합니다3.

동적 바인딩의 장점은 뭐야?

동적 바인딩의 몇 가지 장점으로는 코드의 유연성과 확장성이 향상된다는 점이 있습니다. 동적 바인딩을 사용하면 다양한 유형의 객체에 사용할 수 있는 보다 일반적인 코드를 생성할 수 있습니다. 또한 쉽게 확장 및 수정할 수 있는 보다 모듈화된 코드를 생성할 수 있습니다.

동적 바인딩은 다양한 유형의 객체에서 작동할 수 있는 다형성 코드를 생성할 수 있는 객체 지향 프로그래밍에 특히 유용합니다. 이를 통해 프로그램의 다른 부분에서 사용할 수 있는 재사용 가능한 코드를 더 쉽게 작성할 수 있습니다.

동적 바인딩의 단점은 뭐야?

동적 바인딩의 몇 가지 단점으로는 함수 호출이 컴파일 타임이 아닌 런타임에 해결되므로 정적 바인딩보다 느릴 수 있다는 점이 있습니다. 이로 인해 경우에 따라 성능 오버헤드가 발생할 수 있습니다.

또한 동적 바인딩은 함수 호출이 런타임까지 해결되지 않기 때문에 코드를 이해하고 디버깅하기가 더 어려울 수 있습니다. 이로 인해 프로그램 실행 흐름을 추적하기가 더 어려워질 수 있습니다.

동적 바인딩의 예로는 어떤게 있을까?

동적 바인딩의 몇 가지 예로는 다양한 유형의 객체에서 작동할 수 있는 다형성 코드를 생성할 수 있는 C++의 가상 함수를 들 수 있습니다. 파이썬에서는 동적 바인딩이 광범위하게 사용되는데, 이는 파이썬이 해석 언어이고 컴파일러가 없기 때문입니다. Ruby에서는 동적 바인딩을 사용하여 쉽게 확장 및 수정할 수 있는 보다 모듈화된 코드를 생성할 수 있습니다.

Java에도 동적 바인딩을 구현하는 방법중 하나로 추상 클래스가 있는데, 이게 인터페이스나 상속을 사용하는 것과 어떻게 다를까?

Java에서는 추상 클래스와 인터페이스가 모두 동적 바인딩을 구현하는 데 사용됩니다. 하지만 둘 사이에는 몇 가지 차이점이 있습니다.

추상 클래스는 추상 키워드를 사용하여 선언되는 클래스입니다. 추상 메서드와 구체적인 메서드를 모두 가질 수 있습니다. 추상 메서드는 선언은 되어 있지만 추상 클래스에서 구현되지 않은 메서드입니다. 즉, 추상 클래스를 확장하는 모든 클래스는 추상 메서드를 구현해야 합니다. 추상 클래스는 인스턴스 변수를 가질 수도 있습니다.

인터페이스는 클래스에 대한 컨트랙트를 정의하는 데 사용되는 추상 메서드의 모음입니다. 인터페이스를 구현하는 모든 클래스는 해당 메서드를 모두 구현해야 합니다. 인터페이스는 인스턴스 변수를 가질 수 없습니다.

Java에서는 일반적으로 인터페이스가 코드의 유연성과 확장성을 높여주기 때문에 추상 클래스보다 선호됩니다. 그러나 추상 클래스가 더 적합한 경우도 있습니다.

추상 클래스와 인터페이스로 각각 동적 바인딩에 예제를 보여줄 수 있어?

다음은 Java에서 추상 클래스 및 인터페이스를 사용한 동적 바인딩의 몇 가지 예입니다:

추상 클래스를 사용한 동적 바인딩

abstract class Animal {
    public abstract void makeSound();
}

class Dog extends Animal {
    public void makeSound() {
        System.out.println("Woof!");
    }
}

class Cat extends Animal {
    public void makeSound() {
        System.out.println("Meow!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.makeSound(); // Output: Woof!

        animal = new Cat();
        animal.makeSound(); // Output: Meow!
    }
}

이 예제에서는 makeSound()라는 추상 메서드가 있는 Animal이라는 추상 클래스가 있습니다. 그런 다음 Animal 클래스를 확장하고 makeSound() 메서드를 구현하는 두 개의 클래스를 만듭니다. 마지막으로 각 클래스의 인스턴스를 생성하고 그 인스턴스에서 makeSound() 메서드를 호출합니다. 이 메서드는 추상적이기 때문에 구현은 런타임에 해결됩니다.

인터페이스를 사용한 동적 바인딩

interface Animal {
    public void makeSound();
}

class Dog implements Animal {
    public void makeSound() {
        System.out.println("Woof!");
    }
}

class Cat implements Animal {
    public void makeSound() {
        System.out.println("Meow!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.makeSound(); // Output: Woof!

        animal = new Cat();
        animal.makeSound(); // Output: Meow!
    }
}

이 예제에서는 makeSound()라는 메서드가 있는 Animal이라는 인터페이스가 있습니다. 그런 다음 Animal 인터페이스를 구현하고 makeSound() 메서드를 구현하는 두 개의 클래스를 만듭니다. 마지막으로 각 클래스의 인스턴스를 생성하고 그 인스턴스에서 makeSound() 메서드를 호출합니다. 이 메서드는 인터페이스의 일부이므로 구현은 런타임에 해결됩니다.

명확하게 설명해 줘서 고마워. 코드와 함께 보니 이해가 잘되네

천만에요! 도움이 되어 기쁘네요. 다른 질문이 있으시면 언제든지 알려주세요.

동적 바인딩에 대해 더 자세히 알고 싶은데, 읽어볼 만한 자료를 추천해 줄 수 있어?

물론입니다! 동적 바인딩은 객체 유형에 따라 특정 함수를 선택해 런타임까지 실행할 수 있도록 하는 프로그래밍 개념입니다. 지연 바인딩 또는 런타임 다형성이라고도 합니다.

다음은 동적 바인딩에 대해 자세히 알아볼 수 있는 몇 가지 리소스입니다:

도움이 되었기를 바랍니다! 다른 질문이 있으시면 언제든지 알려주세요.

출처: 빙과의 대화, 2023. 5. 4.
(1) C++의 동적 바인딩 - javatpoint. https://www.javatpoint.com/dynamic-binding-in-cpp.
(2) C++의 동적 바인딩 - GeeksforGeeks. https://www.geeksforgeeks.org/dynamic-binding-in-cpp/.
(3) 동적 프로그래밍 - 위키피디아. https://en.wikipedia.org/wiki/Dynamic_programming.
(4) 정적 바인딩과 동적 바인딩의 차이점은 무엇입니까? https://stackoverflow.com/questions/640974/what-is-the-difference-between-static-and-dynamic-binding.

앞서 Java에서는 일반적으로 인터페이스가 코드의 유연성과 확장성을 높여주기 때문에 추상 클래스보다 선호된다고 했는데 그 이유가 뭘까?

인터페이스는 코드를 더 유연하고 확장 가능하게 만들기 때문에 일반적으로 Java에서 추상 클래스보다 선호됩니다. 클래스는 여러 인터페이스를 구현할 수 있지만 하나의 클래스만 확장할 수 있기 때문입니다.

또한 인터페이스는 객체 간의 느슨한 결합을 허용합니다. 즉, 인터페이스를 사용하는 클래스에 영향을 주지 않고 인터페이스의 구현을 변경할 수 있습니다.

출처: Bing과의 대화, 2023. 5. 4.
(1) Using an Interface vs. Abstract Class in Java | Baeldung. https://www.baeldung.com/java-interface-vs-abstract-class.
(2) [Java] Interface vs Abstract Class 정리. https://velog.io/@gillog/Java-Interface-vs-Abstract-Class-%EC%A0%95%EB%A6%AC.
(3) When to use abstract class or interface?. https://stackoverflow.com/questions/1221512/when-to-use-abstract-class-or-interface.
(4) Abstract class vs Interface in Java. https://stackoverflow.com/questions/10040069/abstract-class-vs-interface-in-java.

결론

앞서 지속적으로 느낀 경험이지만 ChatGPT와는 대화하는 느낌이 들고 BingAI는 검색엔진을 보다 편하게 접근한다는 느낌이 듭니다.

지금까지의 내용을 정리하면 동적 바인딩 이란 런타임에 실행할 메소드를 결정하는 것입니다.

객체지향 언어가 가지는 특징인데요.

객체지향에서 말하는 메시지를 통한 느슨한 결합을 달성하기 위한 장치입니다.

동적 바인딩 이 없다면 객체지향이 가지고 있는 메시지 수신자가 메시지를 해석하고 어떤 메소드를 선택하여 실행할지를 언어적으로 제공해줄 수 없습니다.

동적 바인딩 이라는 언어적 특징을 기술적으로 접근하는 것 보다 무엇을 달성하기 위해 나타났는지를 같이 보는것이 이해의 난이도가 쉽게 느껴집니다.

동적 바인딩을 구현할 수 있는 자바 언어의 장치로는 추상 클래스인터페이스가 있는데요.

추상 클래스보다 인터페이스가 객체에게 역할을 부여하고 메시지의 책임을 강제한다는 측면에서 보다 적합하다고 생각합니다.

이후 스프링에서 동적 바인딩을 활용하여 메시지를 처리하는 형태가 궁금하여 ChatGPT 에게 추가 질문을 해봤습니다.

그러나 만족할만큼 유연한 구조를 제공해주지 않아 직접 찾아봤습니다.

Dope님의 Polymorphism with Spring에서 기대하는 수준의 예시들을 제공해줘서 만족스럽게 읽었습니다.

아래와 같이 전략 패턴을 적용하여 인터페이스를 구현하는 클래스들의 집합을 관리하는 형태로 동적 바인딩을 활용하는 것을 볼 수 있습니다.

@RequiredArgsConstructor
@Service
public class SeeMoreService {

  // SeeMoreStrategy 를 구현한 빈들이 Map 에 담긴다.
  // DIP : 구현체에 의존하지 않고 SeeMoreStrategy 라는 인터페이스에 의존하게 되었다.
  private final Map<String, SeeMoreStrategy> strategyMap;

  // 파라미터가 dto 인 이유는 더보기는 ajax 를 통해 비동기 형식으로 데이터를 가져와야하기 때문에
  // API 요청과 응답을 처리하기 위해서 VO 가 아닌 DTO 타입으로 만들었다.
  public List<VideoVo> findMoreVideo(VideoDto.SeeMoreRequest dto) {
    String strategyKey = dto.getStrategyKey;
    if(!strategyMap.containsKey(strategyKey)) {
      throw new IllegalArgumentException(Message.NOT_FOUND_STRATEGY);
    }
    SeeMoreStrategy strategy = strategyMap.get(strategyKey);
    return strategy.findMoreVideo(dto.toEntity());
  }
}

그 동안 스프링의 Bean을 @Autowired 나 @Qualifier 를 사용해서 동적 바인딩을 어떻게 달성해야 하는가? IoC 컨테이너를 직접 가지고 원하는 빈 들을 가져와야 하나? 가 의문이었습니다.

위의 예제를 보면 역시 IoC 컨테이너에서 원하는 빈 들을 가져와서 활용하는게 맞는 방향이라는 생각이 듭니다.

물론 이는 하나의 예제일 뿐이니 실무에 맞게 동적 바인딩을 달성할 수 있는 구조를 생각해보는 것도 좋다고 생각합니다.

이전 활용

Comments