とりあえず雑記帳(跡地)
では試してみましょう
最終更新:
fujiyan
-
view
演算を追加してみるパート2
それでは同様に、新しい演算「累乗」を追加してみましょう。
累乗
package jp.fujiyan.binaryoperation3.operator;
import jp.fujiyan.binaryoperation3.IBinaryOperator;
/**
* 累乗です。
*
* @author Fujiyan
*/
public class Power implements IBinaryOperator {
private String expression;
private String result;
public String getChoiseString() {
return "累乗";
}
public void calculate(int value1, int value2) {
expression = String.valueOf(value1) + " ^ " + String.valueOf(value2);
result = String.valueOf((long) Math.pow(value1, value2));
}
public boolean isError() {
// エラーが発生することは無いので、常にfalse
return false;
}
public String getErrorMessage() {
// エラーが発生することは無いので、常にnull
return null;
}
public String getExpression() {
return expression;
}
public String getResult() {
return result;
}
}
演算を追加したことによる修正
/*
* オブジェクト指向版
*/
package jp.fujiyan.binaryoperation3;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import jp.fujiyan.binaryoperation3.operator.Addition;
import jp.fujiyan.binaryoperation3.operator.Division;
import jp.fujiyan.binaryoperation3.operator.Multiplication;
import jp.fujiyan.binaryoperation3.operator.Power;//$$$$$修正$$$$$
import jp.fujiyan.binaryoperation3.operator.Subtraction;
/**
* 二項演算です。
*
* @author fujiyan
*/
public class BinaryOperation {
// 入力値の最小
private static final int MIN_VALUE = -99999;
// 入力値の最大
private static final int MAX_VALUE = 99999;
// 選択肢
private static final int FINISH = 0;
// 演算子のリスト
private static List<IBinaryOperator> operatorList = new ArrayList<IBinaryOperator>();
static {
// operatorListの初期化
operatorList.add(new Addition());
operatorList.add(new Subtraction());
operatorList.add(new Multiplication());
operatorList.add(new Division());
operatorList.add(new Power());//$$$$$修正$$$$$
}
/**
* ユーザ入力を返します。
*
* @param prompt プロンプト文
* @return ユーザ入力文字列
*/
private static String input(String prompt) throws IOException {
System.out.println(prompt);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String str = in.readLine();
if (str == null) {
// Ctrl+Zによる中断
throw new EOFException("中断されました。");
}
return str;
}
/**
* 整数値を問い合わせます。
*
* @return 整数値
*/
private static int askValue(int seq) throws IOException {
int value = 0;
boolean invalid = true;
while (invalid) {
// 整数値が入力されるまで
String ret = input(String.valueOf(seq) + "番目の数値を入力してください(" + MIN_VALUE + "~" + MAX_VALUE + "の整数)。");
try {
value = Integer.parseInt(ret);
} catch (NumberFormatException e) {
// 整数値として有効でない文字列
System.out.println("入力された値は整数値ではありません。");
continue;
}
invalid = (value < MIN_VALUE) || (value > MAX_VALUE);
if (invalid) {
// 無効な入力
System.out.println("入力された数値が範囲を超えています。");
}
}
return value;
}
/**
* 操作を問い合わせます。
*
* @return 操作の選択肢
*/
private static int askOperation() throws IOException {
StringBuilder sb = new StringBuilder();
int i = 0;
sb.append(i).append(":").append("終了");
while (i < operatorList.size()) {
sb.append(" ");
sb.append(i + 1).append(":").append(operatorList.get(i).getChoiseString());
i++;
}
String prompt = "操作を番号で選択してください。(" + new String(sb) + ")";
int operation = 0;
boolean invalid = true;
while (invalid) {
// 有効な選択肢が入力されるまで
String ret = input(prompt);
try {
operation = Integer.parseInt(ret);
invalid = (operation < 0) || (operation > operatorList.size());
} catch (NumberFormatException e) {
// 数値として有効でない文字列
}
if (invalid) {
// 無効な入力
System.out.println("正しい番号を選択してください。");
}
}
return operation;
}
/**
* 演算を行います。
*
* @param operation 操作の選択肢
* @param value1 値1
* @param value2 値2
*/
private static void execute(int operation, int value1, int value2) {
IBinaryOperator op = operatorList.get(operation - 1);
op.calculate(value1, value2);
if (op.isError()) {
// エラーあり
System.out.println(op.getErrorMessage());
return;
}
System.out.println(op.getExpression() + " の答えは " + op.getResult() + " です。");
}
/**
* メインメソッドです。
*
* @param args コマンドライン引数
*/
public static void main(String[] args) {
try {
int operation = askOperation();
while (operation != FINISH) {
// "終了"が選択されるまで
int val1 = askValue(1);
int val2 = askValue(2);
execute(operation, val1, val2);
operation = askOperation();
}
System.out.println("終了します。");
} catch (EOFException e) {
// Ctrl+Zによる中断
System.err.println(e.getMessage());
} catch (Exception e) {
// その他例外
System.err.println("なんかまずいことが発生しました。");
e.printStackTrace();
}
}
}
修正箇所が、格段に減りました。package宣言を除けば1箇所です。
オブジェクト指向でない版では、演算毎に実装が異なる処理がプログラム全体に散らばっていましたが、
インターフェースとしてそれを抽出し、分離することによって、プログラマが追加の際に実装すべきポイントが集約されたためです。
インターフェースとしてそれを抽出し、分離することによって、プログラマが追加の際に実装すべきポイントが集約されたためです。
プログラマはインターフェースの実装に注力するだけでよく、そのインターフェースを利用する部分について把握する必要がなくなりました。
そして同時に、追加部分以外の修正を行わないことは、既存の機能に影響を与えることも無いのです。
そして同時に、追加部分以外の修正を行わないことは、既存の機能に影響を与えることも無いのです。