教育サーバーのページ
オンラインテキスト目次
ソフトウエア入門演習

Javaのクラスと継承の実際

次のような問題を考えてみる:

次の仕様

燃費 = 8.0 (Km/L)
タンク容量 = 80.0 (L)
を搭載した自動車をつかって、次のような計算結果を得たい。
  1. 自動車の最初の状態
    ガソリン残量 = 0.0 L.
    全走行距離 = 0.0 Km.
    
  2. 距離 20Km に必要なガソリン量やガソリン 15L を与えて走る距離を試算する(まだ、自動車を走らせもせず、ガソリンを注入してもいない))
    この車は 20.0 Km 走るために 2.5 L のガソリンが必要。
    この車はガソリン 15.0 L 使って 120.0 Km 走る。
    
  3. 自動車にガソリンを 60L 補給し、状態表示。
    ガソリン残量 = 60.0 L.
    全走行距離 = 0.0 Km.
    
  4. 距離 40Km 走らせようとし、状態表示
    ガソリン残量 = 55.0 L.
    全走行距離 = 40.0 Km.
    
  5. 距離 120Km 走らせようとし、状態表示
    ガソリン残量 = 40.0 L.
    全走行距離 = 160.0 Km.
    
  6. 距離 400Km 走らせようとし、状態表示
    ガス欠! 320.0 Km 走りました。
    ガソリン残量 = 0.0 L.
    全走行距離 = 480.0 Km.
    

クラスの構成

オブジェクト指向プログラミングでは、解決すべき問題が与えられたとき、その仕様を策定し、それを実現するために などについて十分考えることが非常に大切である。 クラスなどのコンポーネントはその場で使い捨てるのではなく、今後の仕事に有効に再利用できるように慎重に設計することが求められているからである。 ソフトウエアの開発においては、この段階でのソフトウエア設計がソフトウエアの性能や維持・拡張性を決定するばかりか、それ以降の諸段階の開発効率に重大な影響を与えることが知られている。

プログラミング,特にオブジェクト指向プログラミング設計において、最初からいきなりソースコードレベルで設計することはあまり意味がない。 ソフトウエア設計の全体を効率よく設計するためにUML(統一モデリング言語:Unified Modeling Language)が使われる。 UMLによって、プログラミング開発者だけでなく、システム仕様策定者やシステムを利用する顧客もが共通の『言葉』にとってシステムの詳細を詰めることが可能になる。

下の図はクラス Engine と クラス Car の依存関係を示している。 クラス Car はクラス Engine を継承している。 クラス Engine にはクラス変数 efficient, capacity, remain が、クラス Car にはクラス変数 tdistance があり、それぞれ次の意味がある:

クラス Engine
efficient:燃料効率(燃費「Km/L]、発電率 [KW/L])
capacity:燃料タンク容量 [L]
remain:燃料残量 {L]
クラス Car
tdistance:全走行距離 [Km]
クラス Engine のメソッドは以下のようである:
double getEfficiency()
    燃費の取得
double getRemain()
    残量の取得
double getCapacity()
    タンク容量の取得
void charge(double gas)
    燃料 gas を補給
double needFuel(double amount)
    量 amount(距離/電力)の達成に必要な燃料
double runAmount(double fuel)
    燃料 fuel によって達成される量(距離/電力)
void getInfo()
    情報表示
クラス Engine を継承しているクラス Car のメソッドは以下のようである:
void move(double distance)
    距離 distandce だけ進む。燃料残量を更新し、ガス欠になってときは、
    そこまでの走行距離を表示し、燃料残量をゼロに。全走行距離を更新。
void getInfo()
    全走行距離も表示するようにスーパークラスのメソッドをオーバーライド

Engine クラスの定義

以下に示すように、各クラスコンストラクタでは燃料残量をゼロにし、デフォルト(燃費 10Km/L、タンク容量 30L)、燃費指定、燃費とタンク容量指定の3つを用意した。

┏━━━━━━━━━ Engine.java ━━━━━━

public class Engine {
    private double efficiency; // 燃費 (Km/L) / 発電効率 (KW/L)
    private double capacity;   // タンク容量 (L)
    double remain;	           // ガソリン残量 (L)

    Engine(){
        efficiency = 10.0;
        capacity = 30.0;
        remain = 0.0;
    }

    Engine(double efficient){
        this.efficiency = efficient;
        capacity = 30.0;
        remain = 0.0;
    }
       
    Engine(double efficient, double capa){
        this.efficiency = efficient;
        this.capacity = capa;
        remain = 0.0;
    }

    public double getEfficiency(){ // 燃費の取得
        return efficiency;
    }

    public double getRemain(){ // 残量の取得
        return remain;
    }
	
    public double getCapacity(){ // タンク容量の取得
        return capacity;
    }

    public void charge(double gas){ // 燃料 gas を補給
        if(gas >= this.getCapacity())
            remain = this.getCapacity();
       	else
            remain = gas;
    }

    public double needFuel(double amount){ // 量 amount(距離/電力) の達成に必要な燃料
        return (amount / this.getEfficiency());
    }
	
    public double runAmount(double fuel){  // 燃料 fuel によって達成される量(距離/電力)
        return (fuel * this.getEfficiency());
    }

    public void getInfo(){ // 情報表示
        System.out.println("燃費 = " + this.getEfficiency() + " Km/L.");
        System.out.println("タンク容量 = " + this.getCapacity() + " L.");
        System.out.println("ガソリン残量 = " + getRemain() + " L.");
    }

    /*
    public static void main(String[] args){
        Engine tk1 = new Engine();
        Engine tk2 = new Engine(9.0);
        Engine tk3 = new Engine(7.0, 50.0);

	tk1.getInfo();
	tk2.getInfo();
	tk3.getInfo();
    }
    */
}
注意:このプログラムを単体で動作させるにはmainメソッドの部分をコメント解除(/* */を削除)する必要がある。
┗━━━━━━━━━━━━━━━━━━━━━━━━

演習 oop-1

上のクラス定義において、フィールド、メソッドの役割を詳細に説明せよ。

演習 oop-1+

上のmainメソッド内でgetInfoメソッドを呼ぶ前に、tk1,tk2,tk3のエンジンに それぞれ10L,20L,30Lのガソリンを補給せよ。

Car クラスの定義

以下に示すように、各クラスコンストラクタではスーパークラスを継承することによって、燃料残量をゼロにし、デフォルト(燃費 10Km/L、タンク容量 30L)、燃費指定、燃費とタンク容量指定の3つを用意した。

┏━━━━━━━━━ Car.java ━━━━━━

public class Car extends Engine {
    double tdistance = 0; // 全走行距離

    Car(){
        super();
    }

    Car(double efficient){
        super(efficient);
    }

    Car(double efficient, double capa){
        super(efficient, capa);
    }

    public void move(double distance){ // 距離 distandce だけ進もうとする
        double nf = this.needFuel(distance);
        if(nf > this.remain){
            double randist = this.runAmount(this.remain);
            System.out.println("ガス欠! " + randist + " Km 走りました。");
            this.remain = 0;
            tdistance += randist;
        } else {
            this.remain = this.remain - nf;
            tdistance += distance;
        }
    }

    public void getInfo(){
        super.getInfo();
        System.out.println("全走行距離 = " + tdistance + " Km.");
    }
}
┗━━━━━━━━━━━━━━━━━━━━━━━━

演習 oop-2

上のクラス定義において、フィールド、メソッドの役割とその継承関係について詳細に説明せよ。

演習 oop-3

クラス Engine と Car を使って、以下の結果を得るように、順に
  1. getInfo()
  2. needFuel(dist)
  3. runAmount(fuel)
  4. charge(60.0)
  5. getInfo()
  6. move(40.0)
  7. getInfo()
  8. move(120.0)
  9. getInfo()
  10. move(400.0)
  11. getInfo()
を使う Javaプログラム runCar.java を書いて実行せよ。

% java runCar
---情報----
燃費 = 8.0 Km/L.
タンク容量 = 80.0 L.
ガソリン残量 = 0.0 L.
全走行距離 = 0.0 Km.
----------
この車は 20.0 Km 走るために 2.5 L のガソリンが必要。
この車はガソリン 15.0 L 使って 120.0 Km 走る。
---情報----
燃費 = 8.0 Km/L.
タンク容量 = 80.0 L.
ガソリン残量 = 60.0 L.
全走行距離 = 0.0 Km.
----------
---情報----
燃費 = 8.0 Km/L.
タンク容量 = 80.0 L.
ガソリン残量 = 55.0 L.
全走行距離 = 40.0 Km.
----------
---情報----
燃費 = 8.0 Km/L.
タンク容量 = 80.0 L.
ガソリン残量 = 40.0 L.
全走行距離 = 160.0 Km.
----------
ガス欠! 320.0 Km 走りました。
---情報----
燃費 = 8.0 Km/L.
タンク容量 = 80.0 L.
ガソリン残量 = 0.0 L.
全走行距離 = 480.0 Km.
----------

ソフトウエア入門演習
教育サーバーのページ
mizutani@rsch.tuis.ac.jp