第126回 ダックタイピング と インタフェース
動的型付け言語と静的型付け言語における多態性
オブジェクト指向では、多態性(ポリモーフィズム)という発想がでてくる。この多態性を実現する方法を今回は2つ紹介する。
Perlは動的型付け言語であり、ダックタイピングという手法で、多態性を実現できる。対して、静的型付け言語であるJavaでは上位の型を作ることで多態性を実現できる(今回はインタフェースを用いてみた)。
多態性を用いればif文がなくなるなどの恩恵を受ける事ができる。
(今回はこのif文がなくなる場面については説明はしない)
ダックタイピング
Perlでのタックタイピングを見てみよう。
my $human = Human->new(); my $duck = Duck->new(); my $dog = Dog->new(); $human->touch($duck); $human->touch($dog);
いま、このようにhumanがtouchすると、おのおのの動物が鳴くソースを書いてみる。
$duck(アヒル)は$human(人間)に触られると「ガーガー」と鳴き、
$dog (犬)は$human(人間)に触れると「ワンワン」と鳴くとする。
全体のソース:
use strict; ########## # 人間 ########## package Human; sub new{ my $self = shift; my $class = ref($self) || $self; return bless {}, $class; } sub touch{ my $self = shift; my $o = shift; $o->say(); } ########## # アヒル ########## package Duck; sub new{ my $self = shift; my $class = ref($self) || $self; return bless {}, $class; } sub say{ print 'ガーガー', "\n"; } ########## # 犬 ########## package Dog; sub new{ my $self = shift; my $class = ref($self) || $self; return bless {}, $class; } sub say{ print 'ワンワン', "\n"; } ######### # main ######### package main; sub { my $human = Human->new(); my $duck = Duck->new(); my $dog = Dog->new(); $human->touch($duck); $human->touch($dog); }->();
結果:
ガーガー ワンワン
これは何がすごいかというと、
sub touch{ my $self = shift; my $o = shift; $o->say(); }
の $o->say()の$oが$duckならDuckのsayが呼ばれてる $oが$dogならばDogのsayが呼ばれているところである。
Javaは型を書かないといけない
Javaでは引数に受け取る型を書かないといけないので、DuckとDogを受け取ることができない。
Humanクラスのtouchメソッドに注目してほしい。
public class Human { public Human() { // ただのコンストラクタ } public void touch(Dog dog){ //型を決めないといけない dog.say(); } }
public class Duck { public Duck() { // ただのコンストラクタ } public void say() { System.out.println("ガーガー"); } }
public class Dog { public Dog() { // ただのコンストラクタ } public void say() { System.out.println("ワンワン"); } }
public class Main { /** * @param args */ public static void main(String[] args) { Human human = new Human(); Duck duck = new Duck(); Dog dog = new Dog(); human.touch(duck); human.touch(dog); } }
結果:
コンパイルエラー
インタフェース
そこで、JavaではDuckとDog以外にさらに上位の概念であるAnimalという型を作ってやる。今回はこれをインタフェースで実現する。
public interface Animal { public void say(); }
DuckとDogはこのAnimalを実装し、
Humanのtouchメソッドは、Animal型を受け取るように書き換える。
public class Human { public Human() { // ただのコンストラクタ } public void touch(Animal o){ //型を決めないといけない o.say(); } }
public class Duck implements Animal{ public Duck() { // ただのコンストラクタ } public void say() { System.out.println("ガーガー"); } }
public class Dog implements Animal{ public Dog() { // ただのコンストラクタ } public void say() { System.out.println("ワンワン"); } }
public class Main { /** * @param args */ public static void main(String[] args) { Human human = new Human(); Duck duck = new Duck(); Dog dog = new Dog(); human.touch(duck); human.touch(dog); } }
結果:
ガーガー ワンワン
このように、明示的に型を書かないといけない言語では、
さらに上位の型を作らなければ、柔軟なことをしにくい。