皆さん命名規則守ってますか?
分かりやすいコードを書くためには必要ですよね。
今回は命名規則の中でも、Interfaceについて考えてみましょう。
※タイトルでは言い切ってますが、結局自分たちが書きやすい方法が正解です。
一つ、規約について考えるきっかけにしてみてくださいな。
本題の前に、よく見るサンプルの書き方
多くのプログラミング言語で使用されるInterfaceですが、
皆さんどのように名前つけてますか?
IとかInterfaceをつける書き方
例えばHogeというクラスがあったとして、このクラスにつけるInterfaceを作るとすると、
public class Hoge implements IHoge {
public void doSomething() {
// 何かする
}
}
public interface IHoge {
void doSomething();
}
とか、
public class Home implements HogeInterface {
public void doSomething() {
// 何かする
}
}
public interface HogeInterface {
void doSomething();
}
とか、こんな感じですかね?
(サンプルはJavaで書きます)
Hogeクラスにつけるインタフェースですから、
- 頭に
Iをつける - おしりに
Interfaceをつける
のどちらかをして、インタフェースだと分かるようにしておきましょうと。
まぁこれはいいでしょう。特に文句ないですね。
IとかInterfaceをつける書き方その2
ではこれだとどうでしょう?
public class Dog implements DogInterface {
public void walk() {
// 歩く
}
public void run() {
// 走る
}
}
public interface DogInterface {
void walk();
void run();
}
あぁっ!? さっきと同じなのに、なんか気持ち悪い!
となりますよね?なりませんか?
では、こう書いたらどうでしょう?
public class Dog implements Animal {
public void walk() {
// 歩く
}
public void run() {
// 走る
}
}
// 同じ機能を持った猫も作れる!
public class Cat implements Animal {
public void walk() {
// 歩く
}
public void run() {
// 走る
}
}
// Interfaceの名前を、より適切にする
public interface Animal {
void walk();
void run();
}
Interfaceの名前をAnimalにしたことによって、
Catのクラスに継承しても違和感が無い状態になりました。
問題の書き方
ここまで納得いただけたでしょうか。
では、次に今回問題にしたい書き方。
public class Dog implements AnimalInterface {
public void walk() {
// 歩く
}
public void run() {
// 走る
}
}
public class Cat implements AnimalInterface {
public void walk() {
// 歩く
}
public void run() {
// 走る
}
}
// 末尾に Interface をつける
public interface AnimalInterface {
void walk();
void run();
}
一つ目と二つ目のハイブリッドみたいな形ですね。
この書き方はどうでしょうか。
特に問題なさそうですか?
ではこのAnimalInterfaceを実際に呼び出してみましょう。
// メソッドだけ抜き出し
public void doSomething(){
AnimalInterface dog = new Dog();
dog.walk();
}
public interface Cage(){ // カゴ(檻)ですね
void add(AnimalInterface animal); // カゴに動物を追加
}
どちらの例にしても、ここで欲しいのは動物です。
それがInterfaceであるかどうかは、呼び出し側からしてみれば「どうでもいい」情報です。
そうではなく、
// メソッドだけ抜き出し
public void doSomething(){
Animal dog = new Dog();
dog.walk();
}
public interface Cage(){
void add(Animal animal);
}
このほうが見通しが良い訳です。
それに(こっちの方が重要ですが)呼び出し側が、呼び出すものがInterfaceかどうかなんて気にしなくてすみます。
ですから、Interface名にI(名前)とか、(名前)Interfaceとするのは、
基本的に余り良くないだろう、と言う事です。
HogeInterfaceの書き方は本来のInterfaceの書き方ではない?
そもそも、なぜInterfaceとかをつけるとかつけないとか、そんな話になったのでしょうか。
そうです。最初に挙げた、Hogeクラスに対してInterfaceをつける場合、
クラスとインタフェースを区別するためにHogeInterfaceとします、というお話からです。
そもそも、Interfaceは、ある事象に対して、それが実装するべき内容を定義するためのものですから、
ある一つのクラスの為だけにInterfaceが作られるという事自体が稀な事なのかもしれません。
例えばDogという実装を書く場合InterfaceとしてAnimalを定義する事と、DogInterfaceを定義する事は、明らかに別の事になります。
どちらも今回はDogクラスの為に定義されているものの、
-
Animal: 扱うべき存在の抽象概念についての定義 -
DogInterface:Dogクラスという具体的存在についての定義
であり、定義している内容に違いがあると言う事です。
Interfaceの本来の役割から考えると、扱う存在の抽象概念を定義する使い方の方が、この場合、より適切でしょう。
よって、Hogeという具体的なクラスが存在する前提で作られているHogeInterfaceは本来の使い方から少しずれた使い方なのです。
IとかInterfaceを、つけてはいけないのか?
では、IHogeとかHogeInterfaceのような書き方はあり得ないのでしょうか?
いえ、これが必要になるパターンがありますね?
そうです。DIです。
DIする場合には、互いの依存を切り離すために、Interfaceを介してやりとりする場合がほとんどです。
この時、注入されるべきは明らかにDogである部分に対してAnimalインタフェースを使ってしまうとCatクラスを注入されてしまう可能性があります(Dogにしかないメソッドを実行させたい場合などは、そもそもコンパイルが通りませんね)。
よって、このような場合ではDogInterfaceを介してやりとりさせることで、確実にDogが入ってくることを保証できます。
まとめ
- 基本的に
Interfaceを作る際にはI(名前)とか(名前)Interfaceの形にしない -
Interface名は扱うべき抽象概念を表した名前をつける -
DIなど、確実にクラスと1:1で紐付いたInterfaceが必要な場合は、この限りでない
ちなみに
色々書きましたが、Javaを使ってる方ならListインタフェースとか思い出してもらったら分かりやすいですよね。
後半でInterfaceとは何か?みたいな話に突っ込んでるので、異論等々あるかと思います。
その場合は心の中で(こいつアホだな)と思うだけでなく、出来ればコメントで教えて下さい。