株式会社エス・スリー・フォー

[Java入門]3.4 ガソリンスタンドのシミュレーション

ガソリンスタンドのシミュレーションを行なうには、これを実行してくれるオブジェクトを作らなくてはいけません。 このためのクラスGasStationSimulation を定義することにします。 その中で、コンストラクタを使ってガソリンスタンドのオブジェクトを作り、シミュレーションを実行するのです。

3.4.1 GasStationSimulation クラス

GasStationSimulationクラスのメソッドについて考えましょう。 まず、GasStationクラスのオブジェクトを作るメソッドが必要です。 これをinitメソッドとしましょう。 ガソリンスタンドを作る(GasStationクラスのコンストラクタを呼び出す) ためには、蓄えているガソリンの量をどうにかして決めなくてはいけませんね。 ガソリンの単価も必要です。 これらが決まればとりあえずガソリンスタンドを作ることができます。

オブジェクトができたなら、今度はそれを使うメソッドが必要です。 このメソッドでは、お客さんが来たときに給油量を聞いてガソリンを入れます。 さらに、代金を計算して受け取ります。 これをdealCustomerメソッドとしましょう。

ガソリンの単価や最初の備蓄量、毎回の給油量はどのようにして決めればよいでしょうか。 すぐに思いつくのはソースに直接書いてしまうことですが、これでは何回実行しても同じ結果になってしまうので、面白くありません。 ここはひとつ、キーボードから入力することにしましょう。 そのときには、ユーザーが何を入力すればいいのかがわかるような、メッセージを表示するといいですね。 また、必要な情報はすべて整数で表されていますから、整数だけが入力できればいいはずです。 メッセージを表示して数値を入力するメソッドを用意しましょう。 メッセージの内容は、引数で受け渡します。 このメソッドの名前は、askIntということにします。

ここまでのメソッドをまとめると、次のようになります。

メソッド名 内容
init 単価、ガソリンの初期量を決定してガソリンスタンドを作る
dealCustomer 給油量を聞いてガソリンを入れ、代金を計算して受け取る
askInt メッセージを表示して整数を入力させ、結果の整数を返す

さて、メソッドはこれでよさそうですので、変数のことも考えてみましょう。 一時的な変数は必要になったときに作ればいいので、ここではガソリンスタンドのシミュレーション全体に関わるような変数を考えます。

まず、用意したガソリンスタンドを、変数に入れておかないといけません。 他に何か必要になるでしょうか? 単価はガソリンスタンドに保存されていますし、給油量は毎回入力するので保存する必要はありません。 ガソリンスタンド以外の変数は、特に必要なさそうです。

では、ソースを書いてみることにしましょう。 まずクラスを作って、変数を定義します。

class GasStationSimulation {
    private GasStation aGS_;
}

3.4.2 メソッドの中身

askIntメソッドは、ガソリンスタンドのオブジェクトを作るために必要な単価や給油量を決定するために使うので、まずこのメソッドから考えることにします。 さきほどまとめた表を基に概要を書いてみると、次のようになります。

private int askInt(String message) {
    // メッセージを表示する
    // 整数を入力してもらう
    // 入力された整数を結果として返す
}

3つ仕事をする必要がありますが、なんだかどれも難しそうです。 でも、安心してください。 ちゃんとこういうことを行なうためのとても便利な方法が用意されているのです。 とにかく、どうすればできるのか、ソースを見てみましょう。

private int askInt(String message) {
    try {
      System.out.print(message);
      System.out.flush();
      String line = new BufferedReader(new InputStreamReader(System.in)).readLine();
      return Integer.parseInt(line);
    } catch ( java.io.IOException e ) {
      System.out.println("could not get input. Sorry.");
      return 0;
    }
}

よくわからない書き方や単語がたくさんでています。 でも、これらの記述がどういう意味なのかは、今はわからなくてかまいません。 この本を読み終えるころにはちゃんと理解できるようになっているはずです。 今はただ、こう書けばメッセージを表示したり、キーボードからの入力を受け取ったり、それを整数の値とすることができると思ってください。

なお、これらのメソッドを利用するためには、BufferedReader, InputStreamReaderクラスを参照することをimportでコンパイラに知らせる必要がありますので、ソースの先頭に以下の記述を入れておきます。

import java.io.BufferedReader;
import java.io.InputStreamReader;

残りの2つのメソッドがすべきこと自体はどちらも単純です。 今作ったaskIntメソッドを使って書いてみましょう。

public void init() {
    System.out.println("For the gas station:");
    int initial = askInt("  initial amount? ");
    aGS_ = new GasStation(initial);
    aGS_.setUnitPrice(askInt("  unit price? "));
}

public void dealCustomer() {
    System.out.println("For the cusomer:");
    int amount = askInt("  refuel amount? ");
    int chargedAmount = aGS_.refuel(amount);
    int price = aGS_.price(chargedAmount);
    aGS_.addSales(price);
    System.out.println("  amount: " + chargedAmount + " [liter]");
    System.out.println("  price: " + price + " [yen]");
}

これらのメソッドの中で、initial, amount, chargedAmount, price という4つの変数を定義しています。 このように、メソッド内で作られた変数はローカル変数と呼ばれ、そのメソッドの中でしか使えません。 ここでは、入力された値や計算結果の整数を一時的に保持するために使われています。

new 演算子

initメソッドの最後から2行目に注目してください。

  aGS_ = new GasStation(initial)

この行では、new演算子でGasStationクラスのコンストラクタを呼び出しています。 つまり、新しいガソリンスタンドのインスタンスを作り、aGS_という変数に代入しているのです。

そして、dealCustomer, initメソッドには、aGS_.refuel(amount)aGS_.setUnitPrice(askInt(& unit price? &amp)といった記述が見られますが、これはaGS_という変数に保持されているガソリンスタンドオブジェクトのメソッドを呼び出しているところなのです。

メソッドsetUnitPriceGasStationクラスのオブジェクトすべてに共通するメソッドなので、オブジェクトのかわりにクラス名を指定して GasStation.setUnitPrice(askInt(& unit price? &amp)とすることもできます。 通常、クラス全体で共通なメソッドを呼び出すときはこのようにクラス名を用いますので、これ以降の例ではこの方法をとることにしましょう。

3.4.3 すべては main メソッドから始まる

これでクラスの定義はほぼできましたが、ひとつ重要なことを忘れています。 GasStationクラスのインスタンスは、GasStationSimulationのインスタンスが作ります。 では、GasStationSimulationのインスタンスはいったい誰がどのように作ればいいのでしょう? 実はJavaではクラスごとに mainメソッドを呼ばれる特別なメソッドを用意することができます。

このメソッドは、インタープリタがそのクラスを実行するときに、最初に呼び出されることになっています。 つまり、javaコマンドで引数にクラスを指定して実行すると、そのクラスで定義されているmainメソッドがまず呼び出されます。 HelloWorldクラスを思い出してください。 HelloWorldクラスはmainメソッドだけでできていましたね。

さて、GasStationSimulationクラスにmianメソッドを定義しましょう。 ソースは次のようになります。

public static void main(String[] args) {
    GasStationSimulation simulation = new GasStationSimulation();
    simulation.init();
    simulation.dealCustomer();
}

public static void main(String[] args)というのは決り文句だと思ってください。 また、mainメソッドにはargsという引数がひとつだけあります。 これは、javaコマンドを起動したとき、クラス名以降のコマンドライン引数が順に格納される文字列の配列です。 配列については後ほど 3.6.3 で実際に使う例が出きますので、ここでは説明しません。

メソッドの中身はどうなっているでしょうか。 まず、GasStationSimulationのコンストラクタを呼び出してインスタンスを作っています。 この引数をとらないコンストラクタは、ひとつもコンストラクタを定義しなかった場合に用意されるデフォルトのコンストラクタです。 そして、作ったGasStationSimulationオブジェクトを変数 simulationに代入し、initメソッドとdealCustomerメソッドを順に呼び出しています。

3.4.4 GasStationSimulation クラスのソース

これでGasStationSimulationクラスの定義が出来上がったので、ファイル全体がどうなるか一度見てみることにします。 クラスごとにファイルを分けた方がわかりやすいので、GasStationSimulation.javaとしましょう。 ソースは、$chapter3/ex2/GasStationSimulation.javaに格納されています。

Java: GasStationSimulation.java
import java.io.BufferedReader;
import java.io.InputStreamReader;

class GasStationSimulation {

  private GasStation aGS_;

  private int askInt(String message) {
    try {
      System.out.print(message);
      System.out.flush();
      String line = new BufferedReader(new InputStreamReader(System.in)).readLine();
      return Integer.parseInt(line);
    } catch ( java.io.IOException e ) {
      System.out.println("could not get input. Sorry.");
      return 0;
    }
  }

  public void init() {
    System.out.println("For the gas station:");
    int initial = askInt("  initial amount? ");
    GasStation.setUnitPrice(askInt("  unit price? "));
    aGS_ = new GasStation(initial);
  }

  public void dealCustomer() {
    System.out.println("For the cusomer:");
    int amount = askInt("  refuel amount? ");
    int chargedAmount = aGS_.refuel(amount);
    int price = aGS_.price(chargedAmount);
    aGS_.addSales(price);
    System.out.println("  amount: " + chargedAmount + " [liter]");
    System.out.println("  price: " + price + " [yen]");
  }

  public static void main(String[] args) {
    GasStationSimulation simulation = new GasStationSimulation();
    simulation.init();
    simulation.dealCustomer();
  }

}

C++: GasStationSimulation.h
#ifndef GASSTATIONSIMULATION_H__
#define GASSTATIONSIMULATION_H__

#include <string>
#include "GasStation.h"

class GasStationSimulation {

private:
  GasStation* aGS_;

  int askInt(const std::string& message);

public:
  ~GasStationSimulation();
  void init();
  void dealCustomer();

};

#endif
C++: GasStationSimulation.cpp
#include <iostream>

#include "GasStationSimulation.h"
#include "GasStation.h"

GasStationSimulation::~GasStationSimulation() {
  delete aGS_;
}

int GasStationSimulation::askInt(const std::string& message) {
  std::cout << message << std::flush;
  int result;
  if ( std::cin >> result ) {
    return result;
  }
  std::cout << "could not get input.  sorry." << std::endl;
  return 0;
}

void GasStationSimulation::init() {
  std::cout << "For the gas station:" << std::endl;
  int initial = askInt("  initial amount? ");
  aGS_ = new GasStation(initial);
  int unitPrice = askInt("  unit price? ");
  GasStation::setUnitPrice(unitPrice);
}

void GasStationSimulation::dealCustomer() {
  std::cout << "For the customer:" << std::endl;
  int amount = askInt("  refuel amount? ");
  int chargedAmount = aGS_->refuel(amount);
  int price = aGS_->price(chargedAmount);
  aGS_->addSales(price);
  std::cout << "  amount: " << chargedAmount << " [liter]" << std::endl;
  std::cout << "  price:  " << price << " [yen]" << std::endl;
}
C++: main.cpp
#include "GasStationSimulation.h"

int main() {
  GasStationSimulation simulation;
  simulation.init();
  simulation.dealCustomer();
  return 0;
}
C#: GasStationSimulation.cs
class GasStationSimulation {

  private GasStation aGS_;

  private int askInt(string message) {
    System.Console.Write(message);
    System.Console.Out.Flush();
    try {
      return System.Int32.Parse(System.Console.ReadLine());
    } catch ( System.Exception ) {
      System.Console.WriteLine("could not get input.  sorry.");
      return 0;
    }
  }

  public void init() {
    System.Console.WriteLine("For the gas stations:");
    int initial = askInt("  initial amount? ");
    aGS_ = new GasStation(initial);
    GasStation.unitPrice = askInt("  unit price? ");
  }

  private void dealCustomer() {
    System.Console.WriteLine("For the customer:");
    int amount = askInt("  refuel amount? ");
    int chargedAmount = aGS_.refuel(amount);
    int price = aGS_.price(chargedAmount);
    aGS_.addSales(price);
    System.Console.WriteLine("  amount: " + chargedAmount + " [liter]");
    System.Console.WriteLine("  price:  " + price + " [yen]");
  }

  [System.STAThread]
  static void Main(string[] args) {
    GasStationSimulation simulation = new GasStationSimulation();
    simulation.init();
    simulation.dealCustomer();
  }

}
VB: GasStationSimulation.vb
Class GasStationSimulation

  Private aGS_ As GasStation

  Private Function askInt(ByVal message As String)
    System.Console.Write(message)
    System.Console.Out.Flush()
    Try
      Return System.Int32.Parse(System.Console.ReadLine())
    Catch e As System.Exception
      System.Console.WriteLine("could not get input.  Sorry.")
      Return 0
    End Try
  End Function

  Public Sub init()
    System.Console.WriteLine("For the customer:")
    Dim initial As Integer = askInt("  initial amount? ")
    GasStation.unitPrice = askInt("  unit price? ")
    aGS_ = New GasStation(initial)
  End Sub

  Public Sub dealCustomer()
    System.Console.WriteLine("For the customer:")
    Dim amount As Integer = askInt("  refuel amount? ")
    Dim chargedAmount As Integer = aGS_.refuel(amount)
    Dim price As Integer = aGS_.price(chargedAmount)
    aGS_.addSales(price)
    System.Console.WriteLine("  amount: " + CStr(chargedAmount) + " [liter]")
    System.Console.WriteLine("  price: " + CStr(price) + " [yen]")
  End Sub

  Public Shared Sub Main()
    Dim simulation As GasStationSimulation = New GasStationSimulation()
    simulation.init()
    simulation.dealCustomer()
  End Sub

End Class

3.4.5 コンパイルと実行

ソースが用意できたらコンパイルしてみてください。 コマンドラインから次の下線部の通りに入力して、javacの引数に今作った2つのファイルを指定します。

% javac GasStation.java GasStationSimulation.java

正しく入力されていれば何もメッセージが出力されずにコンパイルが終了します。 もし、エラーメッセージが出力された場合は、もう一度ソースを見直して間違いを修正してください。

コンパイルが終了したら、クラスファイルができていることを確認してください。 クラスファイルができていたら javaコマンドを使って実行しましょう。 実行するには、クラスファイルを作成したディレクトリが、環境変数$CLASSPATHに含まれていなくてはいけません。 現在の作業ディレクトリをあらわす&.&を含めておきましょう。

コマンドラインから次の下線部のように入力して、GasStationSimulationクラスを実行します。

% java GasStationSimulation

メッセージが表示されて、整数の入力待ちになるので、?の後に数字を入力して改行キーを押します。

% java GasStationSimulation
  For the gas station:
    initial amount? 500

    unit price? 120
  For the cusomer:
    refuel amount? 30
    amount: 30 [liter]
    price: 3600 [yen]

ちゃんと実行できたでしょうか? 何度か試してみて、代金の計算が正しいことを確認してください。

prev next