[Java入門]3.3 ガソリンスタンドのクラス
クラスには様々な内容を記述しますが、その中でも特に重要なのは名前です。 名前はクラスを特定するために用いられます。 そこでまず最初に、ガソリンスタンドのクラスに名前を付けることにしましょう。
クラス名の長さには特に制限はありませんが、使える文字は決まっています。 最初の1文字は英字かアンダーバーか$記号、2文字目以降はそれに加えて数字を使うことができます。 英字の大文字と小文字は区別されますから注意してください。 単語ごとに頭文字を大文字にすると、ソースコードの中に現れるクラス名が見やすくなります。 また、名前はそのクラスが何なのかを表すのですから、わかりやすいものを付けるように心がけましょう。
ガソリンスタンドのクラス名は、英語をそのまま使ってGasStationということにします。 名前が決まったので、さっそくJava言語で記述してみましょう。
/* ガソリンスタンド */
class GasStation {
}
classというキーワードに続けてクラス名を書きます。 クラスがどんなものを表すかは中括弧(‘{‘と’}‘)の中に記述しますが、今はまだクラス名だけしか決まっていないので何もありません。
/*から*/間での部分はコメントです。 コメントはコンパイルのときに無視されるので、プログラムの動作には影響しません。 自由に書き入れることができますから、そのソースコードが何を表しているかを説明するために使ってください。 コメントは複数行にわたって書くこともできます。
コメントの最後には必ず*/をつける必要があるので、ごく短いコメントを書きたいときには少し面倒です。そんな場合にはコメントのもう一つの書き方を使いましょう。 //に続けてコメントを書き始めれば、その行の終わりまでがコメントになります。 これを使うとGasStationクラスの定義は次のようになります。
// ガソリンスタンド
class GasStation {
}
3.3.1 ガソリンスタンドにできること: メソッド
クラスの中身を記述するためには、そのクラスがどんなものを表すのかをきちんと決めなくてはいけません。 そこでもう一度、ガソリンスタンドについて考えてみましょう。
まず、ガソリンスタンドができることについてです。 「ガソリンスタンドが」といっていることに注意してください。 オブジェクト指向では、それぞれのオブジェクトを擬人化すると、オブジェクト同士の関係がわかりやすくなります。 最初は少し抵抗があるかもしれませんが、段々慣れてくるのでそういう風にとらえるんだな、と思っておいてください。
ガソリンスタンドは、車やバイクなどにガソリンを入れることができます。 そして商売ですから、代金を請求して受け取ります。 お釣りを出すこともありますが、これは代金をもらうことに含めておいていいでしょう。 もちろん受け取った代金は売上として計上する必要がありますから、これも忘れずに。 とりあえずこの位にしておきましょう。
できることが決まったので、それぞれに名前を付けます。 ここでは次のようにしてみました。
| メソッド名 | 内容 |
|---|---|
refuel |
ガソリンを入れる |
price |
代金を計算する |
addSales |
代金を領収して売上に計上する |
これらの名前にも、クラスメイト同じように好きなものをつけることができますが、頭文字を小文字にして、クラス名と見間違えないようにするのが普通です。 もちろん、複数の単語からなる名前が付けられますので、addSalesのように2つ目の単語からは頭文字を大文字にした方が読みやすくなるでしょう。
これで「できること」は決まりました。 しかし、実際に実行するためには具体的な手順が必要です。 ガソリンスタンドで働く人は、様々なことを覚えなければなりませんね。 例えば、ガソリンを入れる機械の操作方法やお客さんへの対応の仕方などです。 このようなことはマニュアルになっているでしょう。 その中の「ガソリンの入れ方」などの説明が手順です。 この手順のことをメソッドといいます。 先ほど決めたrefuelなどはメソッドの名前なのです。 そのクラスのオブジェクトに何ができるかはそのクラスにどんなメソッドを定義するかによって決まることになります。
メソッドの型
先程、料金を計算するメソッドを考えましたが、いくらになったのかをはっきりさせておかないと、受け取って売上に計上できません。 つまりこのメソッドは結局いくらになったのかを誰かに知らせる必要があります。 こんなときのために、メソッドは結果の値を返すことができるようになっています。 どんな値が返るかはメソッドによって異なりますから、これはメソッドごとに指定しなければなりません。 これを表すのが型です。 ひとつひとつのメソッドについて、型を決めるのです。 料金の場合は数値で表せますが、例えばそこの店長といった人を表すオブジェクトを返すこともあります。 また、その日が営業日かどうかといったYes/No (true/false, 真偽値あるいはbooleanと呼ばれます) などのような単純な値を表す基本型と、どんなオブジェクトかをあらわすための参照型があります。 文字列やオブジェクトは参照型の値です。 すべてのクラスは型として使うことができます。 基本型についてはこの先必要に応じて紹介していきます。 また、第7章に一覧がありますので詳しく知りたい方はそちらを参照してください。 なお、売上を計上するメソッドのように結果を返す必要のないものの場合は、値を返さないということを型で指定します。 この型のことをvoid型といいます。
3.3.2 ガソリンスタンドの情報: 変数
さて、ガソリンスタンドにできることは決まりましたので、今度はそれらを実行するためにどんな情報が必要になるかを考えてみましょう。
まず、ガソリンを入れるためには、どれだけ入るかがわからなくてはいけません。 しかし、これはお客さんによって違うので、ガソリンスタンド側の情報ではありません。
次にガソリン代の計算ですが、これは単価と入れた量がわかればよさそうです。 ガソリンの単価は時期や店によっても変わりますが、問題を簡単にするためにすべてのガソリンスタンドで同じ、ということにしましょう。
また、各ガソリンスタンドにはガソリンタンクがあります。 このタンクの容量と、残っているガソリンの量も情報として持つことにします。 ただし、タンクの容量は通常変化しません。 そしてまた、すべてのガソリンスタンドで同じということにしておきます。
最後に、その日の売上がどのくらいあったかを、各スタンドが情報として持つことにしましょう。 それぞれ名前を付けてまとめると次のようになります。
■ 各変数/メソッドには原書にはなかったアクセス制限: private/public を付加しました。
private な変数/メソッドはクラスの外部から参照/呼び出しができなくなります。
public な変数/メソッドはクラスの外からアクセスできます。 □
■ 原書では tankCapacity, unitPrice および totalSales に対するアクセス(参照/設定)メソッドを定義していません。 が、クラス内の変数がその外部から自由にアクセスできるのがどうにも居心地が悪かったので、変数はすべて private とし、必要に応じて参照/設定メソッドを定義しました。□
| 変数名 | 内容 |
|---|---|
unitPrice_ |
ガソリンの単価。全ガソリンスタンドで共通。日によって変化する。 |
remain_ |
タンクに残っているガソリンの量。各ガソリンスタンドで異なる。 |
tankCapacity_ |
タンクの容量。全ガソリンスタンドで共通。変化しない。 |
totalSales_ |
売上の合計。各ガソリンスタンドで異なる。 |
クラスが持つ情報は変数と呼ばれる、いわば箱のようなものに保持されます。 今、名前を付けたunitPrice_, remain_ などが変数です。 ただし、変数は値を保持するものなので、メソッドで使うことのできる値を返さない型, void型を指定することはできません。
3.3.3 GasStation クラス
必要なメソッドと変数が決まったので、これをクラスに記述してみましょう。 とはいえ、まだ各メソッドの具体的手順については考えていないので、メソッドの中身はコメントにしておきます。 なお、このソースは $chapter3/ex1/GasStation.java に収録されています。
■ メンバ変数名にはその末尾に ‘_‘ を付加しました。□
- Java: GasStation.java
-
/* ガソリンスタンドクラス */ class GasStation { private static final int tankCapacity_ = 1000; private static int unitPrice_; private int remain_; private int totalSales_; public int refuel(int amount) { // 給油する } public int price(int amount) { // 代金を計算する } public void addSales(int price) { // 売上を計上する } public static int tankCapacity() { // タンクの容量を返す } public int totalSales() { // 売上を返す } static public void setUnitPrice(int price) { // 単価を設定する } static public int unitPrice() { // 単価を返す } }
intとvoidが型を表しています。 intは整数です。 本当はガソリンの量は小数で表されるのでintではなくfloatまたはdoubleとするべきなのですが、説明を簡単にするために整数ということにしています。 voidは先ほど述べたように何も返さない型です。
■
- C++: GasStation.h
-
#ifndef GASSTATION_H__ #define GASSTATION_H__ /* ガソリンスタンドクラス */ class GasStation { private: static const int tankCapacity_; static int unitPrice_; int remain_; int totalSales_; public: int refuel(int amount); int price(int amount) const; void addSales(int price); static int tankCapacity(); int totalSales() const; static void setUnitPrice(int price); static int unitPrice(); }; #endif - C++: GasStation.cpp
-
#include "GasStation.h" const int GasStation::tankCapacity_ = 1000; int GasStation::unitPrice_; int GasStation::refuel(int amount) { // 給油する } int GasStation::price(int amount) const { // 代金を計算する } void GasStation::addSales(int price) { // 売上を計上する } int GasStation::tankCapacity() { // タンクの容量を返す } int GasStation::totalSales() const { // 売上を返す } void GasStation::setUnitPrice(int price) { // 単価を設定する } int GasStation::unitPrice() { // 単価を返す }
C#/VB ではtankCapacity, unitPrice および totalSales へのアクセスをプロパティで実装しました。
- C#: GasStation.cs
-
/* ガソリンスタンドクラス */ class GasStation { private static int tankCapacity_ = 1000; private static int unitPrice_; private int remain_; private int totalSales_; public int refuel(int amount) { // 給油する } public int price(int amount) { // 代金を計算する } public void addSales(int price) { // 売上を計上する } public static int tankCapacity { get { // タンクの容量を返す } } public int totalSales { get { // 売上を返す } } static public int unitPrice { set { // 単価を設定する } get { // 単価を返す } } } - VB: GasStation.vb
-
' ガソリンスタンドクラス Class GasStation Private Shared tankCapacity_ As Integer = 1000 Private Shared unitPrice_ As Integer Private remain_ As Integer Private totalSales_ As Integer Public Function refuel(ByVal amount As Integer) As Integer ' 給油する End Function Public Function price(ByVal amount As Integer) As Integer ' 代金を計算する End Function Public Sub addSales(ByVal price As Integer) ' 売上を計上する End Sub Public Shared ReadOnly Property tankCapacity() As Integer Get ' タンク容量を返す End Get End Property Public ReadOnly Property totalSales() As Integer Get ' 売上を返す End Get End Property Public Shared Property unitPrice() As Integer Set(ByVal Value As Integer) ' 単価を設定する End Set Get ' 単価を返す End Get End Property End Class
□
3.3.4 メソッドの中身を書こう
各メソッドでどんなことをすればいいのかがわかったので、中身を記述してみることにしましょう。 3つのメソッドについて順番に考えていきます。
まず、refuelメソッドです。 ガソリンを入れたらタンクの残量は入れた分だけ減らす必要があります。 これは変数reamin_の値を変更すればよさそうです。 このメソッドは実際に入れた量を返すことになっていました。 メソッドが値を返すためにはreturnを使います。 これらを記述するとrefuelメソッドは以下のようになります。 ただし、ここではタンクの残量を考慮していません。
public int refuel(int amount) {
remain_ = remain_ - amount;
return amount;
}
代金を計算するには実際に入れたガソリンの量に単価を掛けます。 したがって、priceメソッドは次のようになります。
public int price(int amount) {
return amount * unitPrice_;
}
最後に代金を売上に計上します。 単純に変数totalSales_に代金を足せばよさそうです。addSalesメソッドは次のようになります。
public void addSales(int price) {
totalSales_ = totalSales_ + price;
}
3.3.5 ガソリンスタンドを建てる: コンストラクタ
せっかくガソリンスタンドのクラスを作ったのですから、使うことを考えなければいけません。 使うというのは、ガソリンを入れたり、代金を受け取ったりしてみることです。 これは、ガソリンスタンドのシミュレーションと言ってもいいでしょう。
ガソリンスタンドをシミュレーションするためには、まずガソリンスタンドのインスタンスを用意する必要があります。 クラスは定義できましたが、インスタンスはどのように作ればよいのでしょうか。
現実の世界では、工事をしてガソリンスタンドを建てます。 建物などを建設することをコンストラクトと言いますが、Javaの世界でも同じようにこの言葉を使います。 コンストラクトという言葉には組み立てるという意味もありますが、人によってはコチラの方がイメージしやすいかも知れません。
ガソリンスタンドを建設するためには、どんなガソリンスタンドを作るのかといったことがわかっていなくてはなりません。 建物の内装工事をしたり、営業を開始する前にタンクにガソリンを用意したりもするでしょう。 どこかにその手順を示しているものが必要です。 これがコンストラクタです。 コンストラクタは一種のメソッドのようなもので、そのクラスのインスタンスを作るときに呼び出されます。
コンストラクタには次のような特長があります。
new演算子を使って呼び出す- 必ずクラスと同じ名前である
- 返す値の型は指定しない
- 引数を渡すことができる
我々のGasStationクラスにもコンストラクタを記述してみましょう。 コンストラクタであらかじめタンクにガソリンを入れておくことにします。 入れておくガソリンの量を引数として渡すことにすると、コンストラクタは次のようになります。
public GasStation(int initial) {
remain_ = initial;
}
3.3.6 GasStation クラスのソース
これでガソリンスタンドを表すGasStationクラスの定義が完成しました。 ここで、今までに出てきたソースをまとめておきます。 このソースは$chapter3/ex2/GasStation.javaに格納されています。
- Java: GasStation.java
-
/* ガソリンスタンドクラス */ class GasStation { // 変数定義 private static final int tankCapacity_ = 1000; private static int unitPrice_; private int remain_; private int totalSales_; // コンストラクタ定義 public GasStation(int initial) { remain_ = initial; } // メソッド定義 public int refuel(int amount) { remain_ = remain_ - amount; return amount; } public int price(int amount) { return amount * unitPrice_; } public void addSales(int price) { totalSales_ = totalSales_ + price; } public static int tankCapacity() { return tankCapacity_; } public int totalSales() { return totalSales_; } static public void setUnitPrice(int price) { unitPrice_ = price; } static public int unitPrice() { return unitPrice_; } }
■
- C++: GasStation.h
-
#ifndef GASSTATION_H__ #define GASSTATION_H__ /* ガソリンスタンドクラス */ class GasStation { private: static const int tankCapacity_; static int unitPrice_; int remain_; int totalSales_; public: explicit GasStation(int initial); int refuel(int amount); int price(int amount) const; void addSales(int price); static int tankCapacity(); int totalSales() const; static void setUnitPrice(int price); static int unitPrice(); }; #endif - C++: GasStation.cpp
-
#include "GasStation.h" const int GasStation::tankCapacity_ = 1000; int GasStation::unitPrice_; GasStation::GasStation(int initial) : remain_(initial) { } int GasStation::refuel(int amount) { remain_ = remain_ - amount; return amount; } int GasStation::price(int amount) const { return amount * unitPrice_; } void GasStation::addSales(int price) { totalSales_ = totalSales_ + price; } int GasStation::tankCapacity() { return tankCapacity_; } int GasStation::totalSales() const { return totalSales_; } void GasStation::setUnitPrice(int price) { unitPrice_ = price; } int GasStation::unitPrice() { return unitPrice_; } - C#: GasStation.cs
-
class GasStation { private static int tankCapacity_ = 1000; private static int unitPrice_; private int remain_; private int totalSales_; public int refuel(int amount) { remain_ = remain_ - amount; return remain_; } public int price(int amount) { return amount * unitPrice_; } public void addSales(int price) { totalSales_ = totalSales_ + price; } public static int tankCapacity { get { return tankCapacity_; } } public int totalSales { get { return totalSales_; } } static public int unitPrice { set { unitPrice_ = value; } get { return unitPrice_; } } } - VB: GasStation.vb
-
' ガソリンスタンドクラス Class GasStation Private Shared tankCapacity_ As Integer = 1000 Private Shared unitPrice_ As Integer Private remain_ As Integer Private totalSales_ As Integer Public Sub New(ByVal initial As Integer) remain_ = initial End Sub Public Function refuel(ByVal amount As Integer) As Integer remain_ = remain_ - amount Return amount End Function Public Function price(ByVal amount As Integer) As Integer Return amount * unitPrice_ End Function Public Sub addSales(ByVal price As Integer) totalSales_ = totalSales_ + price End Sub Public Shared ReadOnly Property tankCapacity() As Integer Get Return tankCapacity End Get End Property Public ReadOnly Property totalSales() As Integer Get Return totalSales_ End Get End Property Public Shared Property unitPrice() As Integer Set(ByVal Value As Integer) unitPrice_ = Value End Set Get Return unitPrice_ End Get End Property End Class
□