第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);
	}

}

結果:

ガーガー
ワンワン

このように、明示的に型を書かないといけない言語では、
さらに上位の型を作らなければ、柔軟なことをしにくい。