第127回 Ruby vs Java ダックタイピングとインタフェースで見る多態性

前回は、Perlで書いたのだけど、
Rubyでも書いてみたので載せます。

動的型付け言語と静的型付け言語における多態性

オブジェクト指向では、多態性ポリモーフィズム)という発想がでてくる。
この多態性を実現する方法を今回は2つ紹介する。

Rubyは動的型付け言語であり、ダックタイピングという手法で、多態性を実現できる。
対して、静的型付け言語であるJavaでは上位の型を作ることで多態性を実現できる(今回はインタフェースを用いてみた)。

ダックタイピング

Rubyでのタックタイピングを見てみよう。

human = Human.new
dog   = Dog.new
duck  = Duck.new

human.touch(dog)
human.touch(duck)

いま、このようにhumanがtouchすると、おのおのの動物が鳴くソースを書いてみる。
duck(アヒル)はhuman(人間)に触られると「ガーガー」と鳴き、
dog (犬)はhuman(人間)に触れると「ワンワン」と鳴くとする。


全体のソース:

class Dog
  def say
    puts 'ワンワン'
  end
end
class Duck
  def say
    puts 'ガーガー'
  end
end
class Human
  def touch(o)
    o.say
  end
end

human = Human.new
dog   = Dog.new
duck  = Duck.new

human.touch(dog)
human.touch(duck)

結果:

ガーガー
ワンワン


これは何がすごいかというと、

class Human
  def touch(o)
    o.say
  end
end

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

}

結果:

ガーガー
ワンワン

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