「継承」と「委譲」
こんにちは
プログラミングをしていて基本的な部分ではあるのですが、「継承」と「委譲」についての役割を明確に切り分けたいので
「継承」と「委譲」とは何か?そして使い分けはどう考えるかまとめておこうと思います。
・「継承」と「委譲」とは
間違いを恐れずにいうとどちらも、あるクラス(基底クラス)の処理を参照・実装する場合に使います。
・継承の場合「extends」や「implements」などを使って既存のクラスの構造をベースに新しいクラスを定義して再利用する仕組み。既存のクラスの変数やメソッドを受け継がせた上で固有の処理を実装していくことになります。
・委譲の場合は対象のクラスのインスタンスを呼び出し元のクラスで作成し、作成したインスタンスからメソッドを呼び出します。
実際の違いはコードを見るとわかります。
サンプルコード "継承"
class Animal {
void cry() {
System.out.println("鳴く");
}
void wolk() {
System.out.println("歩く");
}
}
class Dog extends Animal {
void cry() {
System.out.println("ワンと鳴く");
}
}
class Bird extends Animal {
void cry() {
System.out.println("ホーホケキョと鳴く");
}
void fly() {
System.out.println("飛ぶ");
}
}
Animalという基底クラスをDogクラスとBirdクラスが継承しています。
DogクラスとBirdクラスはAnimalクラスで定義されているメソッドはすべて引き継ぎ、かつ独自に上書きしたり新しいメソッドを定義することができます。
サンプルコード "委譲"
class Message{
void write(String text){
...
}
boolean delete(int target){
...
}
boolean send(String text){
...
}
}
class Mail{
Message message;
String title;
String body;
UserRepository(String title, String body){
message = new Message();
this.title = title;
this.body = body;
}
boolean send(int userId) {
return this.message.send();
}
}
MessageというクラスをMailクラス内でインスタンス化して、sendメソッドを使用しています。これによりMailクラスの役割とは関係のない処理を実装することがないので、Mailクラスを使用するクライアント側で意図しない呼び出しをされることがありません。
どちらの方法でもやっていることに大きな違いが無いように見えるかもしれません
ではどう使い分けるべきか...
・継承を使う時
親となるクラスと子となるクラスの役割が同じ場合。サンプルの場合で言うと犬も鳥も動物という枠組みでは同じ役割を担っています。
仮に役割が別のものが継承したとします。例えばアリクラスを作って、歩く処理を実装したいのでAnimalクラスを継承すると歩く処理に加えて鳴く処理も実装されます。このように不要なメソッドが実装されてしまうと、このクラスを使用するクライアントとなるクラスから意図しない使われ方をしてしまう可能性があるのです。
さらにメリットして、オブジェクト指向では継承すると「多態性(ポリモーフィズム)」の恩恵を受けることができます。これはとても重要なのですが一旦割愛します。下記記事がわかりやすいので参照してください。
オブジェクト指向の多態性(ポリモーフィズム)についてわかりやすく解説
・委譲を使う場合
こちらは大きな役割としては違うが、部分的に処理を委ねたい場合に使用する
インスタンス作成の処理やメソッド呼び出し処理の記述が必要にはなるが、意図しない処理が実装されることはない。
クラスの役割としても親クラスの大枠の中であるわけではなく参照している様なイメージである。
上記内容が全てではないが、オブジェクト指向を理解するのに「継承・委譲」やインターフェースなどの概念を理解するのはとても重要と感じています。
自分も理解出来ていない部分が多いのでまとめながら理解していけたらなと思っています。
下記書籍はオブジェクト指向を学ぶのにとても役立っていますので参考にしてみてください。
Java言語で学ぶデザインパターン入門
オブジェクト指向でなぜつくるのか
この記事が気に入ったらサポートをしてみませんか?