다양한 종류의 다형성이 있으며, 관심있는 것은 일반적으로 런타임 다형성 / 동적 디스패치입니다.
런타임 다형성에 대한 매우 높은 수준의 설명은 메소드 호출이 인수의 런타임 유형에 따라 다른 작업을 수행한다는 것입니다. 객체 자체는 메소드 호출을 해결해야합니다. 이것은 엄청난 유연성을 허용합니다.
이 유연성을 사용하는 가장 일반적인 방법 중 하나는 종속성 주입입니다 . 예를 들어 다른 구현간에 전환하거나 테스트를 위해 모의 객체를 주입 할 수 있습니다. 가능한 한 제한된 수의 선택 만 할 수 있다는 것을 미리 알고 있다면 조건부로 하드 코딩을 시도 할 수 있습니다.
void foo() {
if (isTesting) {
... // do mock stuff
} else {
... // do normal stuff
}
}
이로 인해 코드를 따르기가 어렵습니다. 대안은 해당 foo 조작을위한 인터페이스를 도입하고 해당 인터페이스의 일반 구현 및 모의 구현을 작성하고 런타임시 원하는 구현에 "주입"하는 것입니다. "의존성 주입"은 "올바른 대상을 인수로 전달"하는 복잡한 용어입니다.
실제 예를 들어, 저는 현재 친절한 기계 학습 문제를 해결하고 있습니다. 예측 모델이 필요한 알고리즘이 있습니다. 그러나 다른 기계 학습 알고리즘을 시도하고 싶습니다. 그래서 인터페이스를 정의했습니다. 예측 모델에서 무엇이 필요합니까? 일부 입력 샘플, 예측 및 오류가 제공됩니다.
interface Model {
def predict(sample) -> (prediction: float, std: float);
}
내 알고리즘은 모델을 훈련시키는 팩토리 함수를 사용합니다.
def my_algorithm(..., train_model: (observations) -> Model, ...) {
...
Model model = train_model(observations);
...
y, std = model.predict(x)
...
}
이제 모델 인터페이스를 다양하게 구현했으며 서로 벤치마킹 할 수 있습니다. 이러한 구현 중 하나는 실제로 두 개의 다른 모델을 가져 와서 확장 된 모델로 결합합니다. 이 인터페이스 덕분에
- 내 알고리즘은 특정 모델에 대해 미리 알 필요가 없습니다.
- 모델을 쉽게 교체 할 수 있고
- 모델을 구현할 때 많은 유연성이 있습니다.
다형성의 전형적인 유스 케이스는 GUI에 있습니다. Java AWT / Swing /…과 같은 GUI 프레임 워크에는 다른 구성 요소가 있습니다. 구성 요소 인터페이스 / 기본 클래스는 화면 자체에 페인팅하거나 마우스 클릭에 반응하는 등의 작업을 설명합니다. 많은 구성 요소는 하위 구성 요소를 관리하는 컨테이너입니다. 그러한 컨테이너는 어떻게 스스로 그릴 수 있습니까?
void paint(Graphics g) {
super.paint(g);
for (Component child : this.subComponents)
child.paint(g);
}
여기서 컨테이너는 하위 구성 요소의 정확한 유형에 대해 미리 알 필요가 없습니다. 컨테이너가 Component
인터페이스 를 준수하기 만하면 컨테이너가 단순히 다형성 paint()
메서드 를 호출 할 수 있습니다 . 이를 통해 임의의 새로운 구성 요소로 AWT 클래스 계층 구조를 자유롭게 확장 할 수 있습니다.
소프트웨어 개발 전반에 걸쳐 다형성을 기법으로 적용하여 해결할 수있는 많은 반복적 인 문제가 있습니다. 이러한 반복되는 문제 해결 쌍을 디자인 패턴 이라고 하며 그 중 일부는 같은 이름의 책에 수집됩니다. 이 책의 용어에서 필자의 주입 된 머신 러닝 모델은 “알고리즘 제품군을 정의하고 각 알고리즘을 캡슐화하여 상호 교환 가능하게 만드는” 전략 입니다. 컴포넌트가 서브 컴포넌트를 포함 할 수있는 Java-AWT 예제는 컴포지트 의 예제입니다 .
그러나 모든 디자인이 다형성을 사용할 필요는 없습니다 (단위 테스트를위한 의존성 주입을 가능하게하는 것 이상). 그렇지 않으면 대부분의 문제는 매우 정적 인 것입니다. 결과적으로 클래스와 메소드는 종종 다형성에 사용되지 않고 편리한 네임 스페이스와 예쁜 메소드 호출 구문에 사용됩니다. 예를 들어 많은 개발자들은 account.getBalance()
거의 동등한 함수 호출보다 메소드 호출을 선호합니다 Account_getBalance(account)
. 그것은 완벽하게 훌륭한 접근법이며, 많은“방법”호출은 다형성과 관련이 없습니다.