こんにちは、コイキングです。
本記事では OOP(Object Oriented Programming == オブジェクト指向プログラミング)の説明のうち、抽象化について、説明したいと思います。
1. 抽象化とは?
現実のオブジェクトから核心的な事、共通的な事、繰り返している事を抜き出す事と言えます。
"ジムで運動する事"を用いて、例えてみると、
ある人はスクワットラックでスクワットで足の運動をするし、ある人はスミスマシンでデッドリフトで背中の運動を、ある人はベンチでベンチプレスで胸の筋肉を鍛えるでしょう。
上記の運動する人の共通点を抜き出してみると
運動器具 (スクワットラック、スミスマシン、ベンチ)から
適切な運動方法(スクワット、デッドリフト、ベンチプレス)で
特定の身体(足、背中、胸)を鍛えています。
また、核心的な行為を抜き出してみると'運動する'になります。
Javaでは上記のような抽象化作業を手伝うツールとして、抽象クラスとインターフェースがあります。
以下の例示コードは抽象クラスとインターフェースを用いて、"ジムで運動する事"を抽象化してコードにしたものです。
package objective.basic06;
public abstract class WhoWorkout {
protected int muscle = 10;
// Sub
protected WorkOutTool workOutTool;
protected WorkOut workOut;
protected BodyPart bodyPart;
public WhoWorkout(WorkOutTool workOutTool, WorkOut workOut, BodyPart bodyPart) {
this.workOutTool = workOutTool;
this.workOut = workOut;
this.bodyPart = bodyPart;
}
public abstract void doWorkout(); // Core
}
interface WorkOutTool {
public void setTool();
}
interface WorkOut {
public void execute(BodyPart bodyPart);
}
abstract class BodyPart {
protected int fatigue = 0;
public void setEffect(int fatigue) {
this.fatigue = fatigue;
}
public abstract int getEffect();
}
核心的な行為の"運動する事"は抽象メソッドにて抜き出し、
運動器具、運動方法、特定の身体はインターフェースと抽象クラスの参照変数をコンストラクターの引数そして渡し、ポリモーフィズムを活用することとします。
2. 抽象クラス
1) 抽象クラスとは?
抽象クラスは抽象化を進み、核心的で共通的な行為と属性を定義したクラスです。
抽象化が進んでいるため、抽象クラス自体ではインスタンスを生成することができず、抽象クラスを継承する子クラスのインスタンス用いることだけで抽象クラスの機能が使えます。
抽象クラスで核心的で共通的な行為を定義したメソッドが抽象メソッドです。
こちらの抽象メソッドは継承する子クラスから細かい内容を必ず再定義しないといけません。
※ 抽象クラスの宣言
abstract classクラス名{
}
2) 抽象クラスを使う理由
抽象クラスを使う理由は継承の長所である'維持保守性'と'生産性'を極めるためだと言えます。
共通的な行為を抽象化し抽象クラスに定義しておくと子クラスで同じ機能を定義しなくてよくて、子クラスを実装する時、抽象メソッドの再定義が強制されるため、一定的な形式の子クラスの実装を強制され、維持保守がより楽になります。
また、共通の機能と属性が抽象クラスに実装されているため、共通の機能は実装する必要がなく、抽象メソッドを実装だけすればよいため、生産性が上がります。
3. インターフェース
1) インターフェースとは?
インターフェースも抽象化を手伝う道具です。
抽象クラスは細かいところまで実装されたメソッドを持つことができるが、インターフェースでは抽象メソッドと変数はpublic static finalだけを持つことができます。
抽象クラスが未完成の設計図なら、インターフェースは未完成の設計図がさらに抽象化された基本設計図のようなものです。
※ インターフェース宣言方法
interface インターフェース名 {
}
2) インターフェースを使う理由
インターフェースを継承したクラスからインターフェースに定義した行為の実装を強制する時に使います。
4. 抽象クラスとインターフェースの差
※ 差の整理
抽象クラス | インターフェース | |
---|---|---|
コンストラクターの定義 | O | X |
変数のアクセス制御子の定義 | 制約 X | public static finalのみ |
メソッドのアクセス制御子の定義 | 制約 X | public abstract, public default, public staticのみ |
継承時のキーボード | extends | implements |
多重継承 | X | O |
多重継承の除き、インターフェースができるのは全て抽象クラスでもできるが、実際両方使い道が違います。
1) 継承関係(is-A; 子クラス is 親クラス)の時に抽象クラスを使います。
継承の長所を極めるときに使います。
2) 包含関係(has-A; クラス has インターフェース)の時にインターフェースを使います。
継承の場合、子クラスと親クラスの間は強く結合されます。例えると要らないメソッドも継承されるなど。。
しかし、インターフェースを継承するとインターフェースのメソッドだけ実際することで機能の拡張ができるため、より柔軟な機能拡張ができます。
※ 抽象クラス・インターフェースの使用
package objective.basic06;
public class Person extends WhoWorkout{
public Person(WorkOutTool workOutTool, WorkOut workOut, BodyPart bodyPart) {
super(workOutTool, workOut, bodyPart);
}
@Override
public void doWorkout() {
workOutTool.setTool(); // 運動器具セット
workOut.execute(bodyPart); // 運動方法 / 運動する身体セット
int effect = bodyPart.getEffect();// 運動した後の筋肉増加
muscle += effect;
System.out.println("Get Musle : "+effect+" Total Musle mass is "+ muscle);
}
public static void main(String[] args) {
// 運動器具, 運動方法, 運動する身体をコンストラクターの引数に渡します。
// 引数に渡すインスタンスによって、doWorkout()の結果が変わります。
Person person = new Person(new SquatRack(), new Squat(), new Lag());
person.doWorkout();
}
}
class SquatRack implements WorkOutTool {
@Override
public void setTool() {
System.out.println("To prepare a SquatRack.");
}
}
class Squat implements WorkOut {
@Override
public void execute(BodyPart bodyPart) {
System.out.println("execute Squat");
}
}
class Lag extends BodyPart {
public Lag() {
this.setEffect(2);
}
@Override
public int getEffect() {
if (fatigue < 0) {
return 0;
}
return 2 * fatigue;
}
}
※ 例示コード
https://github.com/leeyoungseung/algorithmBasic/blob/master/algorithm/src/objective/basic06
※ 韓国語のポストは以下のURLで確認できます。
https://koiking.tistory.com/92