オブジェクト指向
Java9

開発経験の薄い私がオブジェクト指向について振り返ってみる

※2018/5/7 githubにソースをアウトプット、遊んで見て下さい。
https://github.com/lunalice/example

【前置き】

最近Rubyを触るようになってオブジェクト指向について振り返る機会があったので少しぽちぽち。
新しい言語を触るとどこにでも現れてくるこのオブジェクト指向とは!?
オブジェクト指向で検索するといろんな考察や解説サイトが引っ掛かるが、
解説してる方々は把握されてオブジェクト指向を謳っているが、調べた側は何となくもやもやする感じありますよね?

偉い人「カプセル化・継承・ポリモーフィズム」

調べてる人「ふんふんふん・・・つまり、どういうことだってばよ?」

偉い人「オブジェクト指向は概念」

調べてる人「宇宙キターーーー!!」

偉い人「実際の物体を作って行く」
偉い人2「違うそうじゃない」

調べてる人「?????」

なんかもう、これだって答えは永遠に出ない命題ではないかと思う。
危うくナルト化してしまいそうなので何となくわかったようなわかってないような皆様そして私、一緒にオブジェクト指向を振り返って見ませんか?

※オブジェクト指向と書くといろんな科学反応がおきる嫌な予感がするので、
当方偽エンジニア故、お叱りよりアドバイスを頂けると幸いです。

【本題】

問題提起、じゃあどう検証して行こうかと考えた所、
文章的な考察だとさっぱりピーマンな気がするので実際コーディングして行こうと思う。
お手柔らかにお願いします。IDEはCloud9で言語はJava。
※問題文わかりにくければごめんなさい。

【問題①】
1分間で40km走るホンダ車がありました。
10分で走り切るコースを走らせた時、走行距離は何㎞になるでしょうか?

これは凄く簡単な問題ですね。開発したくて入った所が派遣雑用で、
泣きながらひたすらVBAで手続き型プログラムを書き続けてきた私に不可能はない(ビキビキ

EXAMPLE_1.java
public class EXAMPLE_1 {
    public static void main(String[] args) {
        String car_name_1 = "ホンダ"; //車の名前
        int speed_1 = 40; // 速度
        int mileage_1 = 0; // 走行距離
        // 10分間走行させる
        for(int i=0;i<10;i++){
            mileage_1 += speed_1;
        }
        System.out.println(car_name_1 + "の走行距離は" + mileage_1 + "です!");
    }
}

⇒ホンダの走行距離は400です!

超簡単ですね!!(ドヤ

【問題②】
上記のコースを1分間で50km走るマツダ車を走らせた時、走行距離は何㎞になるでしょうか?

EXAMPLE_2.java
public class EXAMPLE_2 {
    public static void main(String[] args) {
        String car_name_1 = "ホンダ"; //車の名前
        int speed_1 = 40; // 速度
        int mileage_1 = 0; // 走行距離
        String car_name_2 = "マツダ"; //車の名前
        int speed_2 = 50; // 速度
        int mileage_2 = 0; // 走行距離
        // 10分間走行させる
        for(int i=0;i<10;i++){
            mileage_1 += speed_1;
            mileage_2 += speed_2;
        }
        System.out.println(car_name_1 + "の走行距離は" + mileage_1 + "です!");
        System.out.println(car_name_2 + "の走行距離は" + mileage_2 + "です!");

    }
}

⇒ホンダの走行距離は400です!
⇒マツダの走行距離は500です!

まだまだ余裕ですね。

【問題③】
上記コースを1分間初速50㎞だが走る際2倍の速度で走るF1車を走らせた時、走行距離は何kmになるでしょうか?

EXAMPLE_3.java
public class EXAMPLE_3 {
    public static void main(String[] args) {
        String car_name_1 = "ホンダ"; //車の名前
        int speed_1 = 40; // 速度
        int mileage_1 = 0; // 走行距離
        String car_name_2 = "マツダ"; //車の名前
        int speed_2 = 50; // 速度
        int mileage_2 = 0; // 走行距離
        String car_name_3 = "F1"; //車の名前
        int speed_3 = 50; // 速度
        int mileage_3 = 0; // 走行距離
        // 10分間走行させる
        for(int i=0;i<10;i++){
            mileage_1 += speed_1;
            mileage_2 += speed_2;
            mileage_3 += speed_3*2;
        }
        System.out.println(car_name_1 + "の走行距離は" + mileage_1 + "です!");
        System.out.println(car_name_2 + "の走行距離は" + mileage_2 + "です!");
        System.out.println(car_name_3 + "の走行距離は" + mileage_3 + "です!");
    }
}

⇒ホンダの走行距離は400です!
⇒マツダの走行距離は500です!
⇒F1の走行距離は1000です!

まぁ余裕なんですね。
さて、ここまでが私の思う所の手続き型プログラミングです。

ここから少しづつオブジェクト指向っぽくして行きましょう。
わかりやすい所で車。こいつはホンダ、マツダ、F1という名前を持っているようです。
さらにはこいつらは速度を持っており、車は走る事(振る舞い)で走行距離が蓄積されて行くでしょう。

そんなクラスを一つこさえた所、次のようなクラスが完成しました。

CAR.java
public class CAR {
    protected String name; //名前
    protected int speed; //速度
    protected int mileage; //走行距離

    //コンストラクタ
    public CAR(String name,int speed){
        this.name = name;
        this.speed = speed;
        this.mileage = 0;
    }

    // 走る振る舞い
    public void run(){
        this.mileage = mileage + speed;
    }

    // 名前を返す
    public String getName(){
        return name;
    }

    // 走行距離を返す
    public int getMileage(){
        return mileage;
    }   
}

なんとなく動きそうな気がする!
これを問題③のクラスに反映させてみたいと思います。

EXAMPLE_5.java
public class EXAMPLE_5 {
    public static void main(String[] args) {
        CAR honda = new CAR("ホンダ",40);
        CAR matsuda = new CAR("マツダ",50);
        CAR f1 = new CAR("F1",50);
        // 10分間走行させる
        for(int i=0;i<10;i++){
            honda.run();
            matsuda.run();
            f1.run();
        }
        System.out.println(honda.getName() + "の走行距離は" + honda.getMileage() + "です!");
        System.out.println(matsuda.getName() + "の走行距離は" + matsuda.getMileage() + "です!");
        System.out.println(f1.getName() + "の走行距離は" + f1.getMileage() + "です!");
    }
}

⇒ホンダの走行距離は400です!
⇒マツダの走行距離は500です!
⇒F1の走行距離は500です!

宇宙キタアアアアアアアアアアアアアアア!!
何となくコーディングもすっきりしたような気分になりますね。

しかしまだ問題が残っています。
おわかり頂けただろうか・・・

⇒F1の走行距離は500です!

二倍速で走れてない!?
それもそのはずCARクラスのrunは2倍で走る機能を持っていないのだ。
(コンストラクタで想定してる値の2倍ぶちこめばええやん!ってのは無しで、、、

じゃあどうしよう、1からF1クラス作るの面倒だよなぁ・・・ってなった時、継承が飛び出して来ると思う。

CARを継承したF1を作ったぞい

F1.java
public class F1 extends CAR {

    // コンストラクタ
    public F1(String name,int speed){
        super(name,speed);
    }

    @Override
    public void run(){
        super.mileage = super.mileage + super.speed * 2;
    }
}

ここら辺で苦しむ要素が出て来る。
superだったりthisだったり親のprivateは引き継げなかったり、アノテーションだったり・・・
今回の題材としては逸れると思うので脇に置いておきます。寧ろ詳しい人解説してくれたら泣いて喜ぶ感じの。

F1クラスをプログラムに反映させてみましょう。

EXAMPLE_6.java
public class EXAMPLE_6 {
    public static void main(String[] args) {
        CAR honda = new CAR("ホンダ",40);
        CAR matsuda = new CAR("マツダ",50);
        CAR f1 = new F1("F1",50);
        // 10分間走行させる
        for(int i=0;i<10;i++){
            honda.run();
            matsuda.run();
            f1.run();
        }
        System.out.println(honda.getName() + "の走行距離は" + honda.getMileage() + "です!");
        System.out.println(matsuda.getName() + "の走行距離は" + matsuda.getMileage() + "です!");
        System.out.println(f1.getName() + "の走行距離は" + f1.getMileage() + "です!");
    }
}

⇒ホンダの走行距離は400です!
⇒マツダの走行距離は500です!
⇒F1の走行距離は1000です!

ナイスファイト!
継承した為protectedにしたがこの辺りがオブジェクトのカプセル化なんじゃないかと思う。
利用者は車にエンジンをかけてエンジンがまわって動き始めて・・・って細かい仕様がわからずともrun()メソッドを押せば勝手に動く。
文で説明はしにくい(誤ってる可能性も)が私の認識はそんな感じ。
今回の利用者はmainになっちゃってるけどこれだとまだ違和感を感じる人もいるだろう。
そういうわけで最後の問題

【問題④】
指定された時間のコースで車を走らせて見よう。

つまりどういう事だってばよ・・・?ってなったかもしれない。
時間決めてくれたらforの回数変えて終わりやん!って思う。
だけどここはオブジェクト指向っぽく行こうと思う。

そこで考えたのが以下のコースクラス。

public class COURSE {
    private int minute_course;

    // 時間をセット
    public COURSE(int minute){
        this.minute_course = minute;
    }

    // 車を走らせるメソッド
    public void doStart(CAR car){
        for(int i=0;i<minute_course;i++){
            car.run();
        }
    }
}

何分コースかの属性を持ち車を走らせる事が出来る。
こいつをプログラムに反映させて今回の考察を〆たいと思う。

※今回は16分

EXAMPLE_7.java
import java.util.*;

/**
 * Class Untitled
 */
public class EXAMPLE_7 {
    public static void main(String[] args) {
        List<CAR> car_box = new ArrayList<CAR>(){
            {
                add(new CAR("ホンダ",40));
                add(new CAR("マツダ",50));
                add(new F1("F1",50));
            }
        };
        COURSE course_16 = new COURSE(16);// コースを生成
        for(CAR car:car_box){
            course_16.doStart(car);
            System.out.println(car.getName() + "の走行距離は" + car.getMileage() + "です!");
        }
    }
}

⇒ホンダの走行距離は640です!
⇒マツダの走行距離は800です!
⇒F1の走行距離は1600です!

コングラッチェ!
Sysinして自由に値を変えろとかListじゃなくて配列でいいとか、
コースに車セットしろよとか細かい事は置いておいて・・・

【最後に】

如何でしたか?
今回、手続き型プログラムをオブジェクト指向っぽく変えたわけですが。

このプログラム群はまた新しい車を走らせてくれ!とか、
やっぱり100分のコース走らせろとか、10分と30分のコース走らせろとかという要望があった場合でも、
ちょちょっと値を変えるだけで実装出来ちゃいます。

簡単なプログラムだとコピペコピペで上から順繰りしていけば仕様は満たせると思いますが、
オブジェクト指向する事で変更に柔軟になった!気がする。

今回考察用ですがpaizaみたくSysinでインプットを持たせるとどんな車でどんな速度でも、
どんなに長いコースでも作れそうな気はしますが。今回は控えておきます。

【最近困ってる事】

派遣SESな私のスキルを客観的に見るとJAVA:並、Ruby:初って感じなのは把握してて、
企業様(転活)にお話しを聞きに行くとやはり使う言語には差があり、キャッチアップは必要。それは大丈夫。
6月目途で計画を立ててる為、その間にキャッチアップを行う。なんだが、無い内定うちはポイント絞って抑えられないのがキツイ所です、平日も外回り期間ですしね・・・

自社サービス開発な企業様いつもお世話になっております!!