Proyek Mini: Kalkulator CLI
Menggabungkan semua materi: bangun kalkulator baris perintah dengan class, exception, dan loop.
Saatnya merangkai semuanya
21 modul sudah lewat. Sekarang buktikan: kita bangun kalkulator CLI yang menggabungkan class, constructor, exception handling, loop, dan collection. Ini proyek kecil tapi lengkap, pola yang sama dipakai di aplikasi nyata.
Rancangan
Kalkulator punya:
- Class
Kalkulatordengan method tambah, kurang, kali, bagi - Riwayat perhitungan (List)
- Exception custom untuk pembagian nol
- Loop menu sampai user memilih keluar
Langkah 1: class dan operasi dasar
class PembagiNol implements Exception {
@override
String toString() => 'Error: tidak bisa dibagi nol!';
}
class Kalkulator {
double tambah(double a, double b) => a + b;
double kurang(double a, double b) => a - b;
double kali(double a, double b) => a * b;
double bagi(double a, double b) {
if (b == 0) throw PembagiNol();
return a / b;
}
}Method bagi melempar custom exception alih-alih mengembalikan infinity yang membingungkan.
Langkah 2: riwayat dengan List
class Kalkulator {
final List<String> riwayat = [];
double tambah(double a, double b) {
double hasil = a + b;
riwayat.add('$a + $b = $hasil');
return hasil;
}
// kurang, kali, bagi: pola sama, catat ke riwayat
void tampilRiwayat() {
if (riwayat.isEmpty) {
print('Belum ada riwayat.');
return;
}
print('--- Riwayat ---');
for (var r in riwayat) {
print(r);
}
}
}Setiap operasi mencatat dirinya ke riwayat. Ini contoh state: object mengingat apa yang terjadi padanya.
Langkah 3: program utama
Karena DartPad tidak bisa baca input keyboard interaktif dengan mudah, kita simulasikan dengan daftar perintah:
class PembagiNol implements Exception {
@override
String toString() => 'Error: tidak bisa dibagi nol!';
}
class Kalkulator {
final List<String> riwayat = [];
double hitung(double a, String op, double b) {
double hasil;
switch (op) {
case '+':
hasil = a + b;
break;
case '-':
hasil = a - b;
break;
case '*':
hasil = a * b;
break;
case '/':
if (b == 0) throw PembagiNol();
hasil = a / b;
break;
default:
throw Exception('Operator $op tidak dikenal');
}
riwayat.add('$a $op $b = $hasil');
return hasil;
}
void tampilRiwayat() {
print('--- Riwayat (${riwayat.length} entri) ---');
for (var r in riwayat) {
print(r);
}
}
}
void main() {
var kalk = Kalkulator();
// simulasi input user: [angka1, operator, angka2]
var perintah = [
[10.0, '+', 5.0],
[20.0, '/', 4.0],
[7.0, '/', 0.0], // akan error, ditangkap
[3.0, '*', 3.0],
];
for (var p in perintah) {
try {
double hasil = kalk.hitung(p[0] as double, p[1] as String, p[2] as double);
print('Hasil: $hasil');
} on PembagiNol catch (e) {
print(e);
} catch (e) {
print('Error: $e');
}
}
kalk.tampilRiwayat();
}Catatan teknis: Contoh di atas menyimpan perintah sebagai
[angka1, operator, angka2], jadi pemanggilannyahitung(p[0], p[1], p[2]). Ini contoh kenapa named parameter lebih aman dari positional: kalauhitungpakai named parameter (hitung(a: ..., op: ..., b: ...)), urutan tidak akan jadi masalah. Di proyek nyata, pilih named untuk fungsi dengan 3+ parameter.
Yang sudah dipakai di proyek ini
Ceklis konsep dari seri ini yang muncul:
- Class, object, method (modul 12)
- Constructor implisit + final property (modul 13)
- Custom exception + try-catch (modul 20)
- List dan for-in (modul 10, 7)
- Switch (modul 6)
- String interpolation (modul 4)
- Type cast
as(modul 11)
Tantangan lanjutan
Kalau kalkulator ini sudah jalan, coba kembangkan:
- Tambah operasi pangkat (
^) dan modulo (%) - Simpan riwayat ke file (pakai
dart:io, jalan di lokal bukan DartPad) - Tambah fitur undo: hapus entri riwayat terakhir
- Ubah jadi async: simulasikan tiap hitungan butuh "waktu proses" dengan Future
Selamat! Kamu sudah menempuh 22 modul Dart dari nol. Langkah berikutnya yang natural: seri Flutter, di mana semua fondasi ini dipakai untuk membangun aplikasi beneran.