“어떤 것이 오리(Duck)인지는 그의 행동을 통해 판단해야 한다”라는 개념이 바로 Duck Typing입니다.
달리 말하면, “처음부터 Type이 정해진 것이 아니라, “오리로서 갖춰야 하는 method들이 구현되어 있으면 걔도 오리야”라고 본다는 이야기죠.
즉, 처음부터 타입을 정해놓지 않고, Runtime 시에 해당 개체에 대한 typ이 정해지고 이를 활용해서 유연한 프로그래밍을 할 수 있도록 한다는 이야기입니다.
하지만, “유연함”과 “자유로움”은 늘 “예기치 못했던 Runtime Error”와 같은 말이어서, 실수가 발생하기 쉽죠.
Java의 경우 DuckTyping을 지원하지 않고, python의 경우 DuckTyping을 지원합니다.
Python - supporting Duck Typing
함수에서 argument type를 구분하지 않습니다.
따라서, 내부에 .quack()만 있다면 문제없이 실행되죠.
class Duck: def __init__(self, name:str) -> object: self.name = name def quack(self): print(f"Duck named {self.name} :: QUACK")class Human: def __init__(self, name: str, age: int) -> object: self.name = name self.age = age def quack(self): print(f"Human named {self.name} :: QUACK") def self_introduce(self): print(f"Hi, My name is {self.name} and {self.age} years old")def quack(each_duck: Duck): # duck을 전달받아서 .quack method를 실행합니다. # Duck Object가 넘어오든, Human Object가 넘어오든 상관없이 # .quack() method만 있으면 실행되죠. each_duck.quack()if __name__ == '__main__': # Duck Object와 Human Object를 하나씩 만들어줍니다. duck = Duck("AAA") human = Human("BBB", 10) # 분명히 두 Object의 type은 다릅니다만. print(type(duck)) # <class '__main__.Duck'> print(type(human)) # <class '__main__.Human'> # 내부에 둘다 .quack method가 있으므로 오류가 발생하지 않습니다. quack(duck) # Duck named AAA :: QUACK quack(human) # Human named BBB :: QUACK
Java - not supporting Duck Typing
class는 다음과 같이 정의합니다.
public class Duck { String name; public Duck(String name) { this.name = name; } public void quack() { System.out.printf("Duck named %s :: QUACK", this.name); }}public class Human { String name; public Human(String name) { this.name = name; } public void quack() { System.out.printf("Human named %s :: QUACK", this.name); }}
실행해 보면, 오류와 함께 실행되지 않습니다. 사실 Java에서는 당연한 거죠.
class Main { public static void quack(Duck inputDuck) { inputDuck.quack(); } public static void main(String[] args) throws Exception { Duck duck = new Duck("AAA"); Human human = new Human("BBB"); quack(duck); // Duck named AAA :: QUACK // 다음 오류와 함께 실행되지 않죠. // java: incompatible types: com.company.Human cannot be converted to com.company.Duck quack(human); }}
Java - using Interface
다만, java에서는 interface를 이용해서 비슷한 짓을 할 수 있습니다.
quackable이라는 .quack 메소드를 가진 interface를 만들어서, Human, Duck에서 구현해줍니다.
그럼, 잘 실행되죠 호호. 이게 Java의 Interface를 사용할 때의 강점입니다.
public interface quackable { public void quack();}public class Duck implements quackable { String name; public Duck(String name) { this.name = name; } public void quack() { System.out.printf("Duck named %s :: QUACK", this.name); }}public class Human implements quackable { String name; public Human(String name) { this.name = name; } public void quack() { System.out.printf("Human named %s :: QUACK", this.name); }}
잘 되죠.
class Main { public static void quack(quackable quackableObj) { quackableObj.quack(); } public static void main(String[] args) throws Exception { Duck duck = new Duck("AAA"); Human human = new Human("BBB"); quack(duck); // Duck named AAA :: QUACK quack(human); // Human named BBB :: QUACK }}
Wrap-up
DuckTyping은 “해당 개체의 type은 같은 메소드(그리고 변수)를 가지고 있는지에 따라서 판단한다”라는 개념입니다.
python의 경우 DuckTyping을 지원하고, Java에서는 DuckTyping을 지원하지 않습니다.
그러나, Java에서는 Interface를 이용해서 비슷한 짓을 할 수 있습니다. 제가 보기에는 Java의 경우다 더 명확하고 좋은 것 같아요.