前回に続き, 電卓アプリ(昭和な電卓のシミュレータ)を対象として, ウェブアプリ開発を漸進的に実施してみよう. ...のつもりでしたが,本年度は,第2部は紹介だけに留めます. 前回の作業(加算式電卓)の解答例だけでも確認してください.
今回は,加算式電卓(前回の宿題)を元に, 逐次四則演算機能を追加実装し, 基本的な実務電卓(business calculator)として完成させよう.
省略.
calc.htmlおよびreg.htmlからacc.htmlへの統合・改変の例: (あくまでも例.他の書き方もあり得る.)
...
<h1>加算式電卓</h1>
... // HTMLコンテンツについてはcalc.htmlを元にして適切に変更...
<script id="VIEW"> // VIEW部には変更なし
...
</script>
<script id="REGISTER"> // reg.htmlからREGISTER部をすべて流用
class REGISTER {
...
}
</script>
<script id="MODEL">
let stts = 'res';
let buf = '0';
const dat = new Register('データレジスタ', 4); // データレジスタの準備
const acc = new Register('アキュムレータ', 6); // アキュムレータの準備
function show(reg) { // 引数としてレジスタを追加
if (reg.err) { // そのレジスタがエラーなら電卓全体もエラー状態に
stts = 'err';
disp('Error');
} else if (stts == 'err') { // 電卓全体がエラー状態の場合
disp('Error');
} else {
disp(reg.str()); // レジスタ内容を表示
}
}
function set(k) {
buf = k; // バッファに書込
dat.read(buf); // データレジスタにバッファを書込
}
function upd(k) {
buf += k; // バッファに追加
dat.read(buf); // データレジスタにバッファを追加
}
function exec(k) {
acc.add(dat); // アキュムレータにデータレジスタの数値を加算
// acc.load(acc.val() + dat.val()); // or これでも同じ,むしろ他の演算への拡張性が出現
}
function start() {
stts = 'res'; // 開始時は結果表示中になるので...
...
show(acc); // ...アキュムレータを表示
}
</script>
<script id="CONTROLLER">
function entNum(k) { // 数字入力中には...
...
show(dat); // ...データレジスタを表示
}
function entExe(k) { // 計算したら結果表示中になるので...
...
show(acc); // ...アキュムレータを表示
}
start();
</script>
...
以上の変更で加算式電卓として, 一般ピープル向けの通常の利用方法に対する動作は完全となった. 数字入力→「=」キーの反復によって,加算を正しく重ねてゆける.
しかし,通常とは異なる利用方法... 数字入力せず「=」キー連打した場合の挙動 (状態遷移res→resのアクション)について, これで良いのだろうか?
計算関数exec() の設計思想として, 次の3通りの考え方があるだろう:
妥当性・利便性について各自で熟考し, 計算関数exec() の定義内容を変更しよう. そして,今後の開発過程でも同じ考え方を貫くこと!! (あるいは,動作モードの切替機能を追加実装しても良いだろう.)
どちらにせよ,柔軟性を考慮すれば, 関数exec() の定義を次のように変更しておくべきだろう:
function exec(k, reg) {
acc.add(reg); // アキュムレータにレジスタdatまたはaccの数値を加算
// acc.load(acc.val() + reg.val()); // or これでも同じ,むしろ...
}
加算式電卓acc.html を元に, 四則演算(二項演算子+−×÷の入力・計算)機能を追加実装し, 昭和な逐次演算式の実務電卓bc.html へ改変せよ.
const K = {
gen(c, f, s, l) {
return { 'class': c, 'func': f, 'str': s, 'label': l };
}
...,
B(s, l) { return this.gen('symbol', 'entOp2', s, l); } // 二項演算子キー生成メソッド
};
const keybd = [
[ K.N('7', '7'), ... , K.B('/', '÷') ], // 「÷」キー追加
... // 他の演算子キーも同様に...
];
let op2 = '='; // 二項演算子 // 初期値は'='でも'+'でもOK // '='の場合:'123=' → = 123 = ... accに123を代入 // '+'の場合:'123=' → 0 + 123 = ... 初期値ゼロのaccに123を加算
function exec(k, reg) {
switch (op2) { // 直近の演算op2で切替,現在の入力kではない
// '1+2='→op2='+',k='='
case '=': acc.load(reg.val()); break; // '=123='
case '+': acc.load(acc.val() + reg.val()); break; // '+123='
case '-': ...
case '*': ...
case '/': ...
}
op2 = k; // 現在の入力kを次回exec()時の演算op2に利用
}
function entOp2(k) {
switch (stts) {
case 'err': break;
case 'tmp': op2 = k; stts = 'tmp'; break;
case 'res': op2 = k; stts = 'tmp'; break;
case 'num': exec(k, dat); stts = 'tmp'; break;
}
show(acc);
}
余裕があれば,bc.html に市販の電卓によくある便利機能を追加せよ.
ありません.