5-1. 演習
通貨を使うクラスを考えます。 値を入れると、通貨記号を含めて表示し、また円レートを設定すると、等価な円オブジェクトを返します。
以下の設問において kaitou パッケージを作り、その中に指定されたクラスを 作成しなさい。
なお、テストクラスを用意したので、各設問 において、指示のあるテストクラスを用いてテストを行い、正常であった旨を 報告しなさい。
この教材は git://edu.net.c.dendai.ac.jp/git/spro/5 から取得して下 さい。
問1-1
始めに、コンストラクタに値を入れ、toString で通貨記号付きの文字列を得 られるようにします。 interface は空ですが、 toString は java.lang.Object に登録されているの で使用できます。
kadai/Money1.java
package kadai;
public interface Money1 {
String getPostfix();
String getPrefix();
double getValue();
}
この時、この Money1 を implements し、次の Yen1, Dollar1 クラスの親クラ スになる kaitou.AbstractMoney1 クラスを定義しなさい。
kadai/Yen1.java
package kadai;
import kaitou.AbstractMoney1;
public class Yen1 extends AbstractMoney1 {
public Yen1(double value) {
super(value);
}
@Override
public String getPrefix() {
return "";
}
@Override
public String getPostfix() {
return "円";
}
}
kadai/Dollar1.java
package kadai;
import kaitou.AbstractMoney1;
public class Dollar1 extends AbstractMoney1 {
public Dollar1(double value) {
super(value);
}
@Override
public String getPrefix() {
return "$";
}
@Override
public String getPostfix() {
return "";
}
}
これらに対して、次のようにすると「100.0円」とか「$3.0」が出力されるようにするということです。
import kadai.Dollar1;
import kadai.Money1;
import kadai.Yen1;
public class Test1 {
public static void main(String[] args) {
Money1 m1 = new Yen1(100);
Money1 m2 = new Dollar1(3);
System.out.println(m1);
System.out.println(m2);
}
}
なお、これらをテストするために Yen1Test と Dollar1Test を使用しなさい。
ヒント
テンプレートメソッドを使用します。
問1-2
次に、円レートを設定して、円に換算する仕組みを作ります。 Money2 インターフェイスは Money1 を継承し、getRate メソッドと、換算し た Yen2 が得られる getYen メソッドが定義されます。
kadai/Money2.java
package kadai;
public interface Money2 extends Money1 {
double getRate();
Money2 getYen();
}
前問同様のクラスを次のように定義します。 このクラスが正常に動作するように kaitou.AbstractMoney2 を作りなさい。 但し、kaitou.AbstractMoney2 は kaitou.AbstractMoney1 を継承し、 kadai.Money2 を implements しなさい。
kadai/Yen2.java
package kadai;
import kaitou.AbstractMoney2;
public class Yen2 extends AbstractMoney2 {
public Yen2(double value) {
super(value);
}
@Override
public String getPrefix() {
return "";
}
@Override
public String getPostfix() {
return "円";
}
@Override
public double getRate() {
return 1.0;
}
public static void setYenRate(double r) {
}
}
kadai/Dollar2.java
package kadai;
import kaitou.AbstractMoney2;
public class Dollar2 extends AbstractMoney2 {
public Dollar2(double value) {
super(value);
}
@Override
public String getPrefix() {
return "$";
}
@Override
public String getPostfix() {
return "";
}
private static double rate;
@Override
public double getRate() {
return rate;
}
public static void setYenRate(double r) {
rate=r;
}
}
つまり、これにより次のように 3 ドルを240円に換算できます。
import kadai.Dollar2;
import kadai.Money2;
public class Test2 {
public static void main(String[] args) {
Money2 m = new Dollar2(3);
System.out.println(m);
Dollar2.setYenRate(80);
System.out.println(m.getYen());
}
}
なお、これらをテストするクラス Yen2Test と Dollar2Test を使用しなさい。
問1-3
次に、大小関係を比較できるようにします。 まず、kadai.Money3 インターフェイスは Complarable を継承します。 そのため、値を比較できるようにするため、 getValue メソッドを追加します。 また、 getYen の戻す値の型を Money3 に上書きします。
kadai/Money3.java
package kadai;
public interface Money3 extends Money2, Comparable<Money3>{
Money3 getYen();
}
つぎに、前問同様のクラスを次のように定義します。 但し、新たに kadai.Euro クラスを導入しています。 このクラスが正常に動作するように kaitou.AbstractMoney3 を作りなさい。 但し、kaitou.AbstractMoney3 は kaitou.AbstractMoney2 を継承し、 kadai.Money3 を implements しなさい。 また、 java.lang.Comparable のマニュアルにあるように、 equals メソッド、 hashCode メソッドも実装しなさい。 なおこれらに関しては Eclipse の自動生成の機能を利用しても構わない。
ヒント
equals のシグネチャは boolean equals(Object obj) なので、引数は Object 型です(java.lang.Object のマニュアル参照)。 お金が等しいことを金額が等しいこととするためには、両者を金額比較する必 要があります。 そのためには、 obj を Money3 にキャストする必要があります。 キャストできるかどうかを判定するには、 obj instanceof Money3 でチェッ クします。
ヒント
AbstractMoney3 そのものは、タダでは equals を自動生成できません。 それはAbstractMoney3 はフィールドを持たないからです。 しかし、実際は親クラスの protected なフィールドを参照するような equals を作成したいわけです。 そのため、Eclipse を騙すと、equals を生成してくれます。 つまり、親クラスの protected なフィールドと同じ名前のフィールドを一旦 AbstractMoney3 クラスに書いてから equals を生成し、そのフィールドを消すと、親クラスのフィールドを参照する equals が生成されます。 また、生成するとき、 instanceof を使用するように指定することを忘れずに。
kadai/Yen3.java
package kadai;
import kaitou.AbstractMoney3;
public class Yen3 extends AbstractMoney3 {
public Yen3(double value) {
super(value);
}
@Override
public String getPrefix() {
return "";
}
@Override
public String getPostfix() {
return "円";
}
@Override
public double getRate() {
return 1.0;
}
public static void setYenRate(double r) {
}
}
kadai/Dollar3.java
package kadai;
import kaitou.AbstractMoney3;
public class Dollar3 extends AbstractMoney3 {
public Dollar3(double value) {
super(value);
}
@Override
public String getPrefix() {
return "$";
}
@Override
public String getPostfix() {
return "";
}
private static double rate;
@Override
public double getRate() {
return rate;
}
public static void setYenRate(double r) {
rate=r;
}
}
kadai/Euro.java
package kadai;
import kaitou.AbstractMoney3;
public class Euro extends AbstractMoney3 {
public Euro(double value) {
super(value);
}
@Override
public String getPrefix() {
return "";
}
@Override
public String getPostfix() {
return "Euro";
}
private static double rate;
@Override
public double getRate() {
return rate;
}
public static void setYenRate(double r) {
rate=r;
}
}
なお、これらをテストするクラス Kadai3Test を使用しなさい。
問1-4
次のプログラムを動作させ、プログラムの動きを説明しなさい。
kadai/Test.java
package test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import kadai.Dollar3;
import kadai.Euro;
import kadai.Money3;
import kadai.Yen3;
public class Test {
public static void main(String[] args) {
Money3[] m3 = {new Yen3(100),new Yen3(150),new Yen3(200),
new Dollar3(1),new Dollar3(2), new Dollar3(3),
new Euro(1),new Euro(2),new Euro(3)};
List<Money3> moneyList = Arrays.asList(m3);
System.out.println(moneyList);
Dollar3.setYenRate(115);
Euro.setYenRate(130);
Collections.sort(moneyList);
System.out.println(moneyList);
List<Money3> moneyList2 = moneyList.stream()
.map((x)->x.getYen())
.collect(Collectors.toList());
System.out.println(moneyList2);
}
}