3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

インターフェースを使って責務を明確に定義する

Last updated at Posted at 2018-07-22

概要

Javaのインターフェースを利用して抽象的に表現したコードサンプルを紹介します。

目的

インターフェースを挟むことでメインクラスと個別に実装されたクラスが疎結合となり、クラスの責務が明確になります。またメインクラス側に個別仕様が表現されていないため、個別実装側の仕様変更に影響されることがなくなります。

抽象的でない悪い例

Dog.java
public class Dog {

	public void makeSound() {
		System.out.println("ワンワン");
	}
}
Cat.java
public class Cat {

	public void makeSound() {
		System.out.println("ニャーニャー");
	}
}
Elephant.java
public class Elephant {

	public void makeSound() {
		System.out.println("パオーン");
	}
}
Main.java
public class Main {

	public static void main(String[] args) {

		Dog dog = new Dog();
		dog.makeSound();
		Cat cat = new Cat();
		cat.makeSound();
		Elephant elephant = new Elephant();
		elephant.makeSound();

	}
}

実行結果は以下のようになります。

ワンワン
ニャーニャー
パオーン

メインクラスでは各動物のインスタンスを生成してメソッドを実行しているので、動物が増えたときなどメインクラスにも修正が入ります。

抽象化したコード例

Dogクラス、Catクラス、Elephantクラスに共通する動物という性質はAnimalクラスを継承することで表現します。また犬、猫、象は鳴くという性質を持っているのでSoundableインターフェースを定義します。
本質的な共通機能の継承関係をクラス、能力的な付加機能の継承関係をインターフェースという住み分けにします。
つまり犬は鳴く動物ですが、ウサギは鳴かない動物です。
象は飛ばない動物ですが、ウサギは飛ぶ動物です。
トビウオは動物ではありませんが、飛びます

どういうことかコードを例に見てみましょう。
まずは本質的な共通機能と能力的な付加機能をそれぞれ定義します。

Soundable.java
public interface Soundable {
	public void makeSound();
}
Jumpable.java
public interface Jumpable {
	public void jump();
}
Animal.java
class Animal {
}
Fish.java
class Fish {
}

次に各動物たちに能力インターフェースを適用します。

Dog.java
public class Dog extends Animal implements Soundable, Jumpable {

	@Override
	public void makeSound() {
		System.out.println("ワンワン");
	}

	@Override
	public void jump() {
		System.out.println("ビョーン");
	}
}
Cat.java
public class Cat extends Animal implements Soundable, Jumpable {

	@Override
	public void makeSound() {
		System.out.println("ニャーニャー");
	}

	@Override
	public void jump() {
		System.out.println("ピョーン");
	}
}
Elephant.java
// 象は飛ばないのでJumpableを継承しない
public class Elephant extends Animal implements Soundable {

	@Override
	public void makeSound() {
		System.out.println("パオーン");
	}
}
Rabbit.java
// うさぎは鳴かないのでSoundableは継承しない
public class Rabbit extends Animal implements Jumpable {

	@Override
	public void jump() {
		System.out.println("ぴょんぴょん");
	}
}
FlyingFish.java
// トビウオは動物ではないが飛ぶのでJumpableを継承する
public class FlyingFish extends Fish implements Jumpable {

	@Override
	public void jump() {
		System.out.println("パシャーン");
	}
}

またZooクラスも定義します。

Zoo.java
public class Zoo {

	private static final String[] animalTypes = { "Dog", "Cat", "Elephant", "Rabbit" };

	public Animal takeOut(String animalType)
			throws InstantiationException, IllegalAccessException, ClassNotFoundException {
		return (Animal) Class.forName(animalType).newInstance();
	}

	public List<Animal> takeOutAll() {
		List<Animal> animals = new ArrayList<>();
		for (String animalType : animalTypes) {
			try {
				animals.add(takeOut(animalType));
			} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
				System.out.println("Zoo isn't allowed to have " + animalType);
			}
		}
		return animals;
	}
}

これで準備が整いました。メインクラスは以下のようになります。

Main.java
public class Main {
	public static void main(String[] args) {
		Zoo zoo = new Zoo();
		List<Animal> animals = zoo.takeOutAll();
		System.out.println("連れ出した動物が鳴く");
		animals.stream()
				.filter(Soundable.class::isInstance)
				.map(Soundable.class::cast)
				.forEach(animal -> animal.makeSound());

		System.out.println("連れ出した動物が飛ぶ");
		animals.stream()
				.filter(Jumpable.class::isInstance)
				.map(Jumpable.class::cast)
				.forEach(animal -> animal.jump());
	}
}

実行結果は前例と同じですが、うさぎは鳴かない動物のため、鳴かない結果になります。
一方飛ぶことに関してはうさぎは飛び、象は飛ばない結果になっています。

連れ出した動物が鳴く
ワンワン
ニャーニャー
パオーン
連れ出した動物が飛ぶ
ビョーン
ピョーン
ぴょんぴょん

まとめ

このように抽象化を意識したコードを書いていくと、自然とクラス間が疎結合になり、責務も明確になっていきます。

3
5
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?