Sunday, December 18, 2016

Bab 10. Java Teori dan Implementasi


Bab. 10 Lebih Lanjut Dengan Objek




10.1 Introduksi
Pada dua bab sebelumnya, Anda telah belajar tentang objek dan kelas. Anda telah belajar bagaimana mendefinisikan kelas, menciptakan objek, dan menggunakan objek dari beberapa kelas dalam JAVA API (misalnya, Date, Random, String, StringBuilder, File, Scanner, dan PrintWriter). Bab ini dikhususkan untuk mengenalkan teknik pemrograman fundamental dan penyelesaian masalah dalam pemrograman berorientasi-objek. Bab ini akan menunjukkan bagaimana pemrograman prosedural dan pemrograman berorientasi-objek berbeda.

Fokus di sini adalah merancang kelas. Akan disajikan beberapa contoh untuk mengilustrasikan keuntungan pendekatan berorientasi-objek. Beberapa contoh yang diberikan melibatkan kelas-kelas baru dan menerapkannya dalam aplikasi.


10.2 Objek dan Kelas Immutable

Normalnya, Anda menciptakan suatu objek dan mengijinkan isinya untuk diubah pada waktu yang akan datang. Tetapi, dalam beberapa kesempatan, Anda menginginkan suatu objek yang memiliki yang tidak dapat diubah. Objek semacam itu disebut dengan objek immutable dan kelasnya dikatakan dengan kelas immutable. Kelas String, misalnya, adalah immutable. Jika Anda menghapus metode tetapkanRadius() dalam kelas Lingkaran2 pada kode8.9, maka kelas tersebut akan menjadi immutable, karena radius dideklarasikan private dan tidak bisa diubah tanpa bantuan metode tetapkanRadius().

Jika suatu kelas immutable, maka semua bidang data harus privat dan tidak bisa memuat metode publik semacam tetapkanRadius() untuk mengubah bidang data. Metode publik yang mengubah bidang data privat disebut juga dengan mutator. Suatu kelas dengan semua bidang data privat tanpa mutator belum tentu immutable. Sebagai contoh, kelas Siswa memiliki semua bidang data privat dan tanpa mutator, tetapi bukan merupakan kelas immutable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Siswa {
  private int id;
  private String nama;
  private java.util.Date tanggalDiciptakan;

  public Siswa(int ssn, String namaBaru) {
    id = ssn;
    nama = namaBaru;
    tanggalDiciptakan = new java.util.Date();
  }

  public int dapatId() {
    return id;
  }

  public String dapatNama() {
    return nama;
  }

  public java.util.Date dapatTanggalDiciptakan() {
    return tanggalDiciptakan;
  }
}

Seperti ditunjukkan pada kode di bawah ini, bidang data tanggalDiciptakan dikembalikan menggunakan metode dapatTanggalDiciptakan(). Ini merupakan referensi ke suatu objek Date. Melalui referensi ini, isi tanggalDiciptakan dapat diubah:

public class Test {
  public static void main(String[] args) {
    Siswa siswa = new Siswa(111223333, "Meika");
    java.util.Date tanggalDiciptakan = siswa.dapatTanggalDiciptakan();
    tanggalDiciptakan.setTime(200000); // Sekarang bidang data tanggalDiciptakan berubah!
  }
}

Agar suatu kelas menjadi immutable, maka harus memenuhi tiga persyaratan berikut ini:
1.     Semua bidang data harus privat.
2.     Tidak ada metode mutator.
3.     Tidak ada aksesor yang mengembalikan suatu referensi ke suatu bidang data yang immutable.


10.3 Skop Variabel
Variabel instans dan variabel statik di dalam suatu kelas dikenal juga dengan variabel kelas atau bidang data. Suatu variabel yang didefinisikan di dalam suatu metode disebut dengan variabel lokal. Skop dari variabel suatu kelas adalah keseluruhan kelas, tanpa memandang tempat dimana variabel itu dideklarasikan.


Gambar 10.1 Anggota-anggota kelas dapat dideklarasikan dengan sembarang urutan, dengan satu pengecualian


Variabel dan metode kelas dapat muncul dengan sembarang urutan, seperti yang ditunjukkan pada Gambar 10.1a. Pengecualiannya adalah ketika suatu bidang data diinisialisasi berdasarkan bidang data lain. Pada kasus tersebut, bidang data lain itu harus dideklarasikan terlebih dahulu, seperti ditampilkan pada Gambar 10.1b. Untuk alasan kejelasan dan konsistensi, buku ini mendeklarasikan bidang data di awal setiap kelas.

Anda bisa mendeklarasikan suatu variabel kelas hanya sekali, tetapi Anda bisa mendeklarasikan nama variabel sama di dalam suatu metode berulang kali pada blok-blok yang berbeda.

Jika suatu variabel lokal memiliki nama yang sama dengan suatu varibel kelas, maka variabel lokal berkuasa dan variabel kelas tersembunyi. Sebagai contoh, program berikut ini, x didefinisikan sebagai suatu variabel instans dan sebagai suatu variabel lokal di dalam metode.

public class Foo {
  private int x = 0;// Variabel instans
  private int y = 0;
  public Foo() {
  }

  public void p() {
    int x = 1;// Variabel lokal
    System.out.println("x = " + x);
   System.out.println("y = " + y);
  }
}

Apakah keluaran dari f.p(), dimana f adalah suatu instans dari Foo? Keluaran f.p() adalah 1 untuk x dan 0 untuk y. Berikut adalah alasannya:
·         x dideklarasikan sebagai suatu bidang data dengan nilai awal 0 di dalam kelas, tetapi juga dideklarasikan di dalam metode p() dengan nilai awal 1. x yang ada di dalam metode p() lah yang direferensi oleh statemen System.out.println.
·         y dideklarasikan di luara metode p(), tetapi tetap dapat diakses dari dalam metode tersebut.


10.4 Referensi this
Katakunci this merupakan nama referensi yang menunjuk kepada objek pemanggil itu sendiri. Salah satu kegunaanya adalah untuk mereferensi bidang data yang tersembunyi. Anda perlu mereferensi bidang data tersembunyi di dalam metode untuk menetapkan nilai yang baru.

Gambar 10.2 Katakunci this menunjuk kepada objek pemanggil yang memanggil metode


Suatu variabel statik tersembunyi bisa diakses dengan menggunakan referensi NamaKelas.VariabelStatik. Suatu variabel instans tersembunyi bisa diakses menggunakan katakunci this, seperti yang ditampilkan pada Gambar 10.2a.

Katakunci this memberi cara untuk menunjuk kepada objek yang memanggil suatu metode. Baris this.i = i berarti “menugaskan nilai parameter i kepada bidang data i pada objek pemanggil”. Baris Foo.k = k berarti bahwa nilai parameter k ditugaskan kepada bidang data statik k, yang dipakai bersama oleh semua objek kelas.

Kegunaan lainnya dari katakunci this adalah untuk memampukan suatu konstruktor untuk memanggil konstruktor lainnya pada kelas yang sama. Sebagai contoh, Anda bisa menulis-ulang kelas Lingkaran sebagai berikut:



Baris this(1.0) dalam konstruktor kedua memanggil konstruktor pertama dengan argumen bertipe double.


10.5 Enkapsulasi dan Abstraksi Kelas
Abstraksi kelas merupakan pemisahan implementasi kelas dari penggunaan suatu kelas. Pencipta suatu kelas menjelaskan kelas dan memberitahu pengguna bagaimana cara menggunakannya. Koleksi metode dan bidang data yang dapat diakses dari luar kelas, bersama dengan deskripsi tentang bagaimana anggota-anggota kelas tersebut berperilaku disebut dengan kontrak kelas. Seperti yang ditunjukkan pada Gambar 10.3, pengguna kelas tidak perlu tahu bagaimana kelas diimplementasikan. Detil implementasi dienkapsulasi dan disembunyikan dari pengguna. Hal ini dikenal dengan enkapsulasi kelas. Sebagai contoh, Anda bisa menciptakan suatu objek Lingkaran dan mencari luas suatu lingkaran tanpa perlu mengetahui bagaimana luas lingkaran dihitung.


Gambar 10.3 Abstraksi kelas memisahkan implementasi kelas dari penggunaan kelas


Abstraksi kelas dan enkapsulasi kelas seperti dua sisi suatu koin. Banyak contoh kehidupan nyata yang mengilustrasikan konsep abstraksi kelas. Misalnya adalah suatu komputer. Komputer pribari Anda memiliki beberapa komponen, seperti CPU, memori, motherboard, kipas, dan lain-lain. Setiap komponen bisa dipandang sebagai objek yang memiliki watak dan metode. Agar komponen-komponen tersebut bisa beroperasi bersama, Anda hanya perlu tahu bagaimana setiap komponen digunakan dan bagaimana setiap komponen berinteraksi satu sama lain. Anda tidak perlu mengetahui bagaimana setiap komponen beroperasi secara internal. Implementasi internal setiap komponen dienkapsulasi dan disembunyikan dari Anda. Anda bisa merakit suatu komputer tanpa perlu mengetahui bagaimana setiap komponennya diimplementasikan.

Analogi komputer pribadi tersebut secara tepat menggambarkan pendekatan berorientasi objek. Setiap komponen komputer dapat dipandang sebagai suatu objek kelas. Sebagai contoh, Anda menginginkan suatu kelas yang memodelkan semua jenis kipas di dalam suatu komputer, dengan watak-watak seperti ukuran dan kecepatan dan metode-metode untuk memulai beroperasi dan berhenti. Suatu kipas spesifik dipandang sebagai suatu instans kelas dengan nilai-nilai watak tertentu.

Gambar 10.4 Kelas Hutang memodelkan watak dan metode kelas


Contoh lain adalah pinjaman. Suatu pinjaman tertentu dapat dipandang sebagai objek suatu kelas Hutang. Suku bunga, jumlah pinjaman, dan periode pinjaman adalah beberapa watak kelas Hutang, dan menghitung pembayaran bulanan dan total pembayaran adalah dua metode kelas ini. Ketika Anda membeli sebuah mobil, suatu objek Hutang diciptakan dengan menginstansiasi kelas yang memiliki watak sku bunga, jumlah pinjaman, dan periode pinjaman. Anda kemudian dapat menggunakan metode-metode yang dimiliki kelas tersebut untuk menghitung pembayaran bulanan dan total pembayaran dari hutang Anda. Sebagai pengguna dari kelas Hutang, Anda tidak perlu mengetahui bagaimana metode-metode ini diimplementasikan.

Kode2.8, HitungHutang.java, telah menghadirkan suatu program untuk menghitung pembayaran pinjaman. Program tersebut tidak dapat digunakan-kembali oleh program lain. Salah satu cara untuk mengatasi masalah ini adalah dengan mendefinisikan metode-metode statik untuk menghitung pembayaran bulanan dan total pembayaran. Tetapi cara ini memiliki keterbatasan, misalnya, ketika Anda ingin menggunakan tanggal pada pinjaman tertentu. Cara ideal untuk mengatasi hal ini adalah dengan menciptakan suatu objek yang mengikat watak informasi pinjaman dengan tanggal secara bersama. Gambar 10.4 menunjukkan diagram kelas UML untuk kelas Hutang.

Diagram UML pada Gambar 10.4 berperan sebagai kontrak untuk kelas Hutang. Pada buku ini, Anda akan memainkan kedua peran sebagai pengguna kelas maupun sebagai pengembang kelas. Penggunda dapat memakai kelas tanpa mengetahui bagaimana kelas diimplementasikan. Diasumsikan bahwa kelas Hutang telah tersedia, Anda bisa menulis suatu program uji yang menggunakan kelas tersebut (kode10.1).

Kode10.1 UjiKelasHutang.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.util.Scanner;

public class UjiKelasHutang {
  /** Metode utama */
  public static void main(String[] args) {
    // Menciptakan Scanner
    Scanner masukan = new Scanner(System.in);

    // Memasukkan suku bunga tahunan
    System.out.print(
      "Masukkan suku bunga tahunan, misalnya, 8.25: ");
    double sukuBungaTahunan = masukan.nextDouble();

    // Masukkan jumlah tahun
    System.out.print("Masukkan jumlah tahun sebagai suatu integer: ");
    int jumlahTahun = masukan.nextInt();

    // Masukkan jumlah pinjaman
    System.out.print("Masukkan jumlah pinjaman, misalnya, 120000.95: ");
    double jumlahPinjaman = masukan.nextDouble();

    // Menciptakan suatu objek Hutang
    Hutang hutang =
      new Hutang(sukuBungaTahunan, jumlahTahun, jumlahPinjaman);

    // Menampilkan tanggal pinjaman, pembayaran bulanan, dan pembayaran total
    System.out.printf("Hutang dibuat pada %s\n" +
     "Pembayaran bulanan sebesar %.2f\nPembayaran total sebesar %.2f\n",
     hutang.dapatTanggalPinjaman().toString(), hutang.dapatPembayaranBulanan(),
     hutang.dapatPembayaranTotal());
  }
}

Metode main membaca suku bunga, periode pembayaran, dan jumlah pinjaman; menciptakan suatu objek Hutang; dan mendapatkan pembayaran bulanan (baris 29) dan pembayaran total (baris 30) menggunakan metode-metode instans dalam kelas Hutang.

Kelas Hutang dapat diimplementasikan pada kode10.2 sebagai berikut:

Kode10.2 Hutang.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class Hutang {
  private double sukuBungaTahunan;
  private int jumlahTahun;
  private double jumlahPinjaman;
  private java.util.Date tanggalPinjaman;

  /** Konstruktor Default */
  public Hutang() {
    this(2.5, 1, 1000);
  }

  /** Menciptakan suatu objek Hutang dengan suku bunga tahunan,
      jumlah tahun, dan jumlah pinjaman tertentu
    */
  public Hutang(double sukuBungaTahunan, int jumlahTahun,
     double jumlahPinjaman){
    this.sukuBungaTahunan = sukuBungaTahunan;
    this.jumlahTahun = jumlahTahun;
    this.jumlahPinjaman = jumlahPinjaman;
    tanggalPinjaman = new java.util.Date();
  }

  /** Mengembalikan sukuBungaTahunan */
  public double dapatSukuBungaTahunan() {
    return sukuBungaTahunan;
  }

  /** Menetapkan sukuBungaTahunan yang baru */
  public void tetapkanSukuBungaTahunan(double sukuBungaTahunan) {
    this.sukuBungaTahunan = sukuBungaTahunan;
  }

  /** Mengembalikan jumlahTahun */
  public int dapatJumlahTahun() {
    return jumlahTahun;
  }

  /** Menetapkan jumlahTahun yang baru */
  public void tetapkanJumlahTahun(int numberOfYears) {
    this.jumlahTahun = jumlahTahun;
  }

  /** Mengembalikan jumlahPinjaman */
  public double dapatJumlahPinjaman() {
    return jumlahPinjaman;
  }

  /** Menetapkan jumlahPinjaman yang baru*/
  public void tetapkanJumlahPinjaman(double loanAmount) {
    this.jumlahPinjaman = jumlahPinjaman;
  }

  /** Menghitung pembayaran bulanan */
  public double dapatPembayaranBulanan() {
    double sukuBungaBulanan = sukuBungaTahunan / 1200;
    double pembayaranBulanan = jumlahPinjaman * sukuBungaBulanan / (1 -
     (Math.pow(1 / (1 + sukuBungaBulanan), jumlahTahun * 12)));
    return pembayaranBulanan;
 }

  /** Menghitung total pembayaran */
  public double dapatPembayaranTotal() {
    double pembayaranTotal = dapatPembayaranBulanan() * jumlahTahun * 12;
    return pembayaranTotal;
  }

  /** Mengembalikan tanggal pinjaman */
  public java.util.Date dapatTanggalPinjaman() {
    return tanggalPinjaman;
  }
}

Dari perspektif pengembang kelas, suatu kelas didesain agar bisa digunakan oleh banyak konsumen. Agar dapat digunakan pada aplikasi yang lebih luas, suatu kelas harus menyediakan cara memodifikasi melalui konstruktor, bidang data, dan metode.

Kelas Hutang memiliki dua konstruktor, empat metode dapat, tiga metode tetapkan, dan beberapa metode untuk menghitung pembayaran bulanan dan pembayaran total. Anda bisa menciptakan suatu objek Hutang menggunakan konstruktor tanpa-argumen atau menggunakan konstruktor dengan tiga argumen: suku bunga tahunan, jumlah tahun, dan jumlah pinjaman. Ketika suatu objek Hutang diciptakan, tanggalnya disimpan pada bidang data tanggalPinjaman. Metode dapatTanggalPinjaman mengembalikan tanggal pembuatan pinjaman. Tiga metode dapat, dapatSukuBungaTahunan, dapatJumlahTahun, dan dapatJumlahPinjaman, mengembalikan secara berturut-turut suku bunga tahunan, jumlah tahun pembayaran, dan jumlah pinjaman. Semua bidang data dan metode dalam kelas ini terikat dengan instans kelas Hutang secara spesifik. Oleh karena itu semua bidang data dan metode dalam kelas ini adalah variabel dan metode instans.


10.6 Cara Berpikir Berorientasi Objek
Bab 1-7 mengenalkan teknik pemrograman elementer untuk menyelesaikan masalah menggunakan loop, metode, dan array. Teknik pemrograman tersebut meletakkan pondasi yang kokoh untuk pemrograman berorientasi objek. Kelas memberikan fleksibilitas dan modularitas untuk membangung perangkat lunak yang dapat didaur-ulang atau dipakai kembali. Bagian ini akan memperbaiki solusi terhadap suatu masalah yang diintroduksi pada Bab. 3 menggunakan pendekatan berorientasi objek. Dari perbaikan-perbaikan yang dilakukan, Anda akan memperoleh pengetahuan akan perbedaan antara pemrograman prosedural dengan pemrograman berorientasi objek. Anda juga diharapkan mampu melihat beberapa keuntungan pengembangan kode yang dapat didaur-ulang menggunakan kelas dan objek.

Kode3.5, HitungBMI.java, telah menyajikan suatu program untuk menghitung indeks massa tubuh. Kode tersebut tidak dapat digunakan kembali oleh program lain. Untuk membuatnya dapat didaur-ulang, definisikan suatu metode statik untuk menghitung indeks massa tubuh sebagai berikut:

public static double dapatBMI(double berat, double tinggi)

Metode ini berguna untuk menghitung BMI pada berat dan tinggi badan tertentu. Tetapi, metode ini memiliki keterbatasan. Dimisalkan Anda ingin mengaitkan berat dan tinggi dengan nama dan tanggal lahir seseorang, maka Anda perlu mendeklarasikan variabel-variabel terpisah untuk menyimpan nilai-nilai ini. Cara ideal untuk melakukannya adalah dengan menciptakan suatu objek yang memuat nilai-nilai tersebut. Karena nilai-nilai tersebut terikat dengan objek individual tertentu, maka harus disimpan dalam bidang-bidang data instans. Anda bisa mendefinisikan suatu kelas bernama BMI, seperti yang ditampilkan pada Gambar 10.5.


Gambar 10.5 Kelas BMI mengenkapsulasi informasi BMI.


Asumsikan bahwa kelas BMI telah tersedia, kode10.3 menyajikan suatu program uji yang menggunakan kelas ini.

Kode10.3 GunakanKelasBMI.java

1
2
3
4
5
6
7
8
9
10
11
public class GunakanKelasBMI {
  public static void main(String[] args) {
    BMI bmi1 = new BMI("Krista Simanungkalit", 18, 145, 70);
    System.out.println("BMI untuk "+ bmi1.dapatNama() + " adalah "
     + bmi1.dapatBMI() + " "+ bmi1.dapatStatus());

    BMI bmi2 = new BMI("Tobat Sinaga", 215, 70);
    System.out.println("BMI untuk "+ bmi2.dapatNama() + " adalah "
     + bmi2.dapatBMI() + " "+ bmi2.dapatStatus());
  }
}

Keluaran

BMI untuk Krista Simanungkalit adalah 20.81 normal
BMI untuk Tobat Sinaga adalah 30.85 sangat gemuk

Baris 3 menciptakan suatu objek bmi1 untuk Krista Simanungkalit dan baris 7 menciptakan suatu objek bmi2 untuk Tobat Sinaga. Anda bisa menggunakan metode-metode instans dapatNama(), dapatBMI(), dan dapatStatus() untuk mengembalikan informasi BMI di dalam suatu objek BMI.

Kelas BMI dapat diimplementasikan pada kode 10.4 sebagai berikut:

Kode10.4 BMI.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class BMI {
  private String nama;
  private int usia;
  private double berat; // dalam pound
  private double tinggi; // dalam inci
  public static final double KILOGRAM_PER_POUND = 0.45359237;
  public static final double METER_PER_INCI = 0.0254;

  public BMI(String nama, int usia, double berat, double tinggi) {
    this.nama = nama;
    this.usia = usia;
    this.berat = berat;
    this.tinggi = tinggi;
  }

  public BMI(String nama, double berat, double tinggi) {
    this(nama, 20, berat, tinggi);
  }

  public double dapatBMI() {
    double bmi = berat * KILOGRAM_PER_POUND /
     ((tinggi * METER_PER_INCI) * (tinggi * METER_PER_INCI));
    return Math.round(bmi * 100) / 100.0;
  }

  public String dapatStatus() {
    double bmi = dapatBMI();
    if (bmi < 16)
      return "sangat kurus";
    else if (bmi < 18)
      return "kurus";
    else if (bmi < 24)
      return "normal";
    else if (bmi < 29)
      return "gemuk";
    else if (bmi < 35)
      return "sangat gemuk";
    else
      return "terlalu gemuk";
  }

  public String dapatNama() {
    return nama;
  }

  public int dapatUsia() {
    return usia;
  }

  public double dapatBerat() {
    return berat;
  }

  public double dapatTinggi() {
    return tinggi;
  }
}

Formula matematika untuk menghitung BMI diberikan menggunakan berat dan tinggi diberikan pada bagian 3.10. Metode instans dapatBMI() mengembalikan nilai BMI. Karena berat dan tinggi adalah bidang data instans di dalam objek, metode dapatBMI() dapat menggunakan kedua bidang data tersebut untuk menghitung BMI untuk objek.

Metode instans dapatStatus() mengembalikan suatu string yang merepresentasikan BMI. Interpretasinya juga diberikan pada bagian 3.10.

Contoh ini mendemonstrasikan beberapa keuntungan paradigma berorientasi objek dibandingkan dengan paradigma prosedural. Paradigma prosedural berfokus pada perancangan metode. Paradigma berorientasi objek menggandeng data dan metode di dalam objek. Perancangan perangkat lunak menggunakan paradigma berorientasi objek berfokus pada objek dan operasi-operasi pada objek. Pendekatan berorientasi objek menggabungkan kekuatan paradigma prosedural dengan suatu dimensi tambahan yang mengintegrasikan data dengan operasi-operasi ke dalam objek.

Dalam pemrograman prosedural, data dan operasi terpisah, dan metodologi ini membutuhkan pengiriman data kepada metode. Pemrograman berorientasi objek menempatkan data dan operasi-operasi yang melekat dengan data tersebut di dalam suatu objek. Pendekatan ini mampu menyelesaikan masalah yang ada pada pemrograman prosedural. Pendekatan pemrograman berorientasi objek bercermin pada apa yang terjadi di dunia nyata, dimana semua objek berhubungan dengan atribut dan aktivitas. Menggunakan objek memampukan pendaur-ulangan kode dan membuat program lebih mudah dipelihara dan dimodifikasi.


10.7 Komposisi Objek
Suatu objek dapat memuat objek yang lain. Relasi antar keduanya disebut dengan komposisi. Pada kode10.1, Anda mendefinisikan suatu kelas BMI untuk memuat suatu bidang data String. Relasi antara BMI dan String merupakan suatu komposisi.

Komposisi sebenarnya adalah suatu kasus spesial dari relasi agregasi. Agregasi memodelkan hubungan adalah-suatu dan merepresentasikan relasi kepemilikan antara dua objek. Objek pemilik disebut dengan objek pengagregat dan kelasnya dinamai dengan kelas pengagregat. Objek subjek atau objek yang dimiliki disebut dengan objek teragregat dan kelasnya dinamai dengan kelas teragregat.

Suatu objek bisa saja dimiliki oleh beberapa objek pengagregat. Jika suatu objek secara eksklusif dimiliki oleh satu objek, maka relasi antara kedua objek tersebut disebut dengan komposisi. Sebagai contoh, “seorang siswa memiliki suatu nama” adalah suatu relasi komposisi antara kelas Siswa dengan kelas Nama, sedangkan “seorang siswa memiliki suatu alamat” adalah suatu relasi agregasi antara kelas Siswa dengan kelas Alamat, karena suatu alamat bisa dipakai bersama oleh beberapa siswa. Dalam UML, suatu diamond terisi dilekatkan pada suatu kelas pengagregat (misalnya, kelas Siswa) untuk menandai hubungan komposisi dengan suatu kelas teragregat (misalnya, kelas Nama), dan suatu diamond kosong dilekatkan pada suatu kelas pengagregat (misalnya, kelas Siswa) untuk menandai hubungan agregasi dengan suatu kelas teragregat (misalnya, kelas Alamat), seperti yang ditampilkan pada Gambar 10.6.

Gambar 10.6 Seorang siswa memiliki suatu nama dan suatu alamat

Setiap kelas yang terlibat di dalam suatu relasi dapat menentukan multiplisitas. Suatu multiplisitas dapat berupa suatu angka atau suatu interval untuk menentukan berapa banyak objek kelas yang terlibat di dalam relasi tersebut. Karakter * berarti banyaknya objek yang terlibat adalah tak-terhingga, dan interval m..n berarti bahwa jumlah objek yang terlibat seharusnya adalah antara m sampai n. Pada Gambar 10.6, setiap siswa hanya memiliki satu alamat, dan setiap alamat bisa dipakai oleh sampai dengan 3 siswa. Setiap siswa hanya memiliki satu nama, dan setiap nama unik untuk setiap mahasiswa.

Suatu relasi agregasi biasanya direpresentasikan sebagai suatu bidang data di dalam kelas pengagregat. Sebagai contoh, relasi pada Gambar 10.6 dapat disajikan sebagai berikut:


Agregasi dapat terjadi antar objek sesama kelas. Sebagai contoh, seseorang dapat memiliki seorang supervisor. Ini diilustrasikan pada Gambar 10.7.


Gambar 10.7 Satu orang dapat memiliki satu supervisor

Dalam relasi, “seseorang memiliki seorang supervisor”, seperti ditunjukkan pada Gambar 10.7, seorang supervisor dapat direpresentasikan sebagai suatu bidang data di dalam kelas Orang, sebagai berikut:

public class Orang {
  // Tipe data adalah kelasnya sendiri
  private Orang supervisor;
 ...
}

Jika seseorang memiliki beberapa supervisor, seperti yang ditunjukkan pada Gambar 10.8a, maka Anda bisa menggunakan suatu array untuk menyimpan beberapa supervisor, seperti ditampilkan pada Gambar 10.8b:

Gambar 10.8 Seseorang bisa memiliki beberapa supervisor


10.8 Mendesain Kelas Pelajaran
Filosopi buku ini adalah mengajar dengan contoh dan belajar dengan latihan. Buku ini menyediakan banyak contoh untuk mendemonstrasikan pemrograman berorientasi objek. Tiga bagian ke depan akan menawarkan beberapa contoh dalam mendesain kelas.

Dimisalkan Anda ingin mengolah informasi tentang pelajaran. Setiap pelajaran memiliki suatu nama dan para siswa yang terdaftar. Anda diharapkan bisa menghapus/menambah seorang siswa dari/ke pelajaran tertentu. Anda bisa menggunakan suatu kelas untuk memodelkan pelajaran, seperti tertampil pada Gambar 10.9.

Gambar 10.9 Kelas Pelajaran memodelkan pelajaran-pelajaran


Suatu objek Pelajaran dapat diciptakan menggunakan konstruktor Pelajaran(String namaPelajaran) dengan melewatkan suatu nama pelajaran. Anda bisa menambahkan siswa-siswa kepada pelajaran menggunakan metode tambahSiswa(String siswa), menghapus seorang siswa dari pelajaran menggunakan metode buangSiswa(String siswa), dan mengembalikan semua siswa pada pelajaran menggunakan metode dapatSiswa(). Dimisalkan bahwa kelas Pelajaran telah tersedia, kode10.5 disajikan sebagai suatu program uji untuk menciptakan dua pelajaran dan menambahkan siswa kepada keduanya.

Kode10.5 UjiPelajaran.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class UjiPelajaran {
  public static void main(String[] args) {
    Pelajaran pelajaran1 = new Pelajaran("Fisika");
    Pelajaran pelajaran2 = new Pelajaran("Biologi");

    pelajaran1.tambahSiswa("Vivian Siahaan");
    pelajaran1.tambahSiswa("Patricia Butet");
    pelajaran1.tambahSiswa("John Sangar");

    pelajaran2.tambahSiswa("Vivian Siahaan");
    pelajaran2.tambahSiswa("Hasiholan Stark");

    System.out.println("Jumlah siswa dalam pelajaran1: "
      + pelajaran1.dapatJumlahSiswa());
    String[] siswa = pelajaran1.dapatSiswa();
    for (int i = 0; i < pelajaran1.dapatJumlahSiswa(); i++)
      System.out.print(siswa[i] + ", ");

    System.out.println();
    System.out.print("Jumlah siswa dalam pelajaran2: "
      + pelajaran2.dapatJumlahSiswa());
  }
}

Keluaran

Jumlah siswa dalam pelajaran1: 3
Vivian Siahaan, Patricia Butet, John Sangar,
Jumlah siswa dalam pelajaran2: 2

Kelas Pelajaran diimplementasikan pada kode10.6, yang menggunakan suatu array untuk menyimpan siswa-siswa untuk pelajaran tertentu. Metode tambahSiswa (baris 10) menambahkan seorang siswa ke dalam array. Kapanpun seorang siswa baru ditambahkan kepada pelajaran tertentu, jumlahSiswa diinkremen. Metode dapatSiswa mengembalikan array tersebut. Metode buangSiswa (baris 27) ditinggalkan kosong sebagai latihan.


Kode10.6 Pelajaran.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Pelajaran {
  private String namaPelajaran;
  private String[] siswa = new String[100];
  private int jumlahSiswa;

  public Pelajaran(String namaPelajaran) {
    this.namaPelajaran = namaPelajaran;
  }

  public void tambahSiswa(String siswa1) {
    siswa[jumlahSiswa] = siswa1;
    jumlahSiswa++;
  }

  public String[] dapatSiswa() {
    return siswa;
 }

  public int dapatJumlahSiswa() {
    return jumlahSiswa;
 }

  public String dapatNamaPelajaran() {
    return namaPelajaran;
  }

  public void buangSiswa(String siswa) {
   // dibiarkan kosong untuk latihan
  }
}

Ukuran array ditetapkan 100 (baris 3). Ketika Anda menciptakan suatu objek Pelajaran, suatu objek array diciptakan. Secara sederhana dapat dikatakan bahwa objek Pelajaran memuat suatu array.

Pengguna dapat menciptakan suatu objek Pelajaran, dan memanipulasinya melalui metode-metode publik tambahSiswa, buangSiswa, dapatJumlahSiswa, dan dapatSiswa. Namun, pengguna tidak perlu mengetahui bagaimana metode-metode tersebut diimplementasikan. Kelas Pelajaran mengenkapsulasi implementasi internal.


10.9 Mendesain Kelas untuk Tumpukan
Ingat bahwa suatu tumpukan merupakan suatu struktur data yang memuat data dengan gaya last-in, first-out, seperti yang ditampilkan pada Gambar 10.10:

Gambar 10.10 Suatu tumpukan yang memuat data dengan gaya last-in, first-out


Tumpukan memiliki banyak terapan. Sebagai contoh, kompiler menggunakan suatu tumpukan untuk mengolah pembagian metode. Ketika suatu metode dipanggil, parameter dan variabel lokalnya didorong ke dalam suatu tumpukan. Ketika suatu metode memanggil metode lain, parameter dan variabel lokal dari metode yang baru didorong ke dalam tumpukan. Ketika metode yang dipanggil selesai dieksekusi dan kembali kepada metode pemanggil, memori yang diokupasi dibebaskan dari tumpukan.
Anda bisa mendefinisikan suatu kelas untuk memodelkan tumpukan. Untuk alasan penyederhanaan, diasumsikan tumpukan memuat nilai-nilai int, dan diberikan nama TumpukanInteger. Diagram UML kelas TumpukanInteger ditampilkan pada Gambar 10.11.

Diasumsikan implementasi kelas TumpukanInteger telah tersedia, pada kode10.7 disediakan suatu program uji untuk menggunakan kelas tersebut untuk menciptakan suatu tumpukan (baris 3), menyimpan sepuluh integer 0, 1, 2, ..., dan 9 (baris 6), dan menampilkannya dalam urutan yang terbalik (baris 9).


Gambar 10.11 Kelas TumpukanInteger mengenkapsulasi penyimpanan tumpukan dan menyediakan beberapa operasi untuk memanipulasi tumpukan


Kode10.7 UjiTumpukanInteger.java

1
2
3
4
5
6
7
8
9
10
11
public class UjiTumpukanInteger {
  public static void main(String[] args) {
    TumpukanInteger tumpukan = new TumpukanInteger();

    for (int i = 0; i < 10; i++)
      tumpukan.dorong(i);

    while (!tumpukan.kosong())
      System.out.print(tumpukan.hapus() + " ");
  }
}


Bagaimana Anda mengimplementasikan kelas TumpukanInteger? Elemen-eleman di dalam tumpukan disimpan di dalam suatu array bernama elemen. Ketika Anda menciptakan suatu tumpukan, array tersebut juga diciptakan. Konstruktor tanpa-argumen menciptakan suatu array dengan kapasitas default 16. Variabel ukuran menghitung jumlah elemen di dalam tumpukan, size – 1 adalah indeks elemen teratas di dalam tumpukan, seperti tertampil pada Gambar 10.12. Untuk suatu tumpukan kosong, ukuran adalah 0.

Kelas TumpukanInteger diimplementasikan pada kode10.8. Metode-metode kosong(), intip(), hapus(), dan dapatUkuran() mudah untuk diimplementasikan. Untuk mengimplementasikan dorong(int nilai), nilai ditugaskan kepada elemen[ukuran] jika ukuran < kapasitas (baris 24). Jika tumpukan penuh (misalnya, ukuran >= kapasitas), suatu array baru diciptakan dengan kapasitas dua kali dari kapasitas sekarang (baris 19), isi array sekarang disalin kepada array yang baru (baris 20), dan referensi array baru ditugaskan kepada array sekarang di dalam tumpukan (baris 21).


Gambar 10.12 Kelas TumpukanInteger mengenkapsulasi penyimpanan tumpukan dan menyediakan beberapa operasi untuk memanipulasi tumpukan


Kode10.8 TumpukanInteger.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class TumpukanInteger {
  private int[] elemen;
  private int ukuran;
  public static final int KAPASITAS_DEFAULT = 16;

  /** Menciptakan suatu tumpukan dengan kapasitas default 16 */
  public TumpukanInteger(){
    this(KAPASITAS_DEFAULT);
  }

  /**  Menciptakan suatu tumpukan dengan kapasitas tertentu */
  public TumpukanInteger(int kapasitas){
    elemen = new int[kapasitas];
  }

  /** Mendorong suatu integer baru ke dalam tumpukan */
  public void dorong(int nilai) {
    if (ukuran >= elemen.length) {
      int[] temp = new int[elemen.length * 2];
      System.arraycopy(elemen, 0, temp, 0, elemen.length);
      elemen = temp;
    }

    elemen[ukuran++] = nilai;
  }

  /** Mengembalikan dan menghapus elemen teratas dari tumpukan */
  public int hapus() {
    return elemen[--ukuran];
  }

  /** Mengembalikan elemen teratas dari tumpukan */
  public int intip() {
    return elemen[ukuran - 1];
  }

  /** Menguji apakah tumpukan kosong */
  public boolean kosong() {
    return ukuran == 0;
  }

  /** Mengembalikan jumlah elemen di dalam tumpukan */
  public int dapatUkuran() {
    return ukuran;
  }
}


10.10 Mendesain Kelas TebakTanggal
Kode3.3, TebakUltah.java, dan kode7.6, TebakUltahMenggunakanArray.java, telah menyajikan dua program untuk menebak hari ulang tahun seseorang. Kedua program menggunakan data sama yang dikembangkan menggunakan paradigma prosedural. Mayoritas kode pada kedua program tersebut adalah untuk mendefinisikan lima himpunan data. Anda tidak bisa menggunakan kembali kode pada kedua program itu. Untuk membuat program dapat didaur-ulang, didesain kelas untuk mengenkapsulasi data, seperti didefinisikan pada Gambar 10.13.

Gambar 10.13 Kelas TebakTanggal mendefinisikan data untuk menebak hari ulang tahun


Perhatikan bahwa dapatNilai didefinisikan sebagai suatu metode statik karena tidak bergantung pada objek kelas TebakTanggal tertentu. Kelas TebakTanggal mengenkapsulasi tanggal sebagai anggota privat. Pengguna kelas ini tidak perlu mengetahui bagaimana diimplementasikan. Semua yang perlu diketahui oleh pengguna adalah bagaimana menggunakan metode dapatNilai mengakses tanggal. Pemanggilan metode dapatNilai(noHimp, baris, kolom) akan memberikan nilai balik berupa tanggal pada baris dan kolom tertentu. Misalnya, dapatNilai(1, 0, 0) menghasilkan 2.

Diasumsikan bahwa kelas TebakTanggal telah tersedia, kode10.9 disajikan sebagai suatu program uji yang menggunakan kelas ini.

Kode10.9 GunakanKelasTebakTanggal.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.Scanner;

public class GunakanKelasTebakTanggal {
  public static void main(String[] args) {
    int tanggal = 0; // Tanggal yang akan ditentukan
    int jawaban;

    // Menciptakan Scanner
    Scanner masukan = new Scanner(System.in);

    for (int i = 0; i < 5; i++) {
      System.out.println("Apakah ultah Anda dalam himpunan" + (i + 1) + "?");
      for (int j = 0; j < 4; j++) {
        for (int k = 0; k < 4; k++)
          System.out.print(TebakTanggal.dapatNilai(i, j, k) + " ");
        System.out.println();
      }

      System.out.print("\nMasukkan o untuk Tidak dan 1 Untuk Ya: ");
      jawaban = masukan.nextInt();

      if (jawaban == 1)
        tanggal += TebakTanggal.dapatNilai(i, 0, 0);
    }

    System.out.println("Hari Ultah Anda adalah " + tanggal);
  }
}

Keluaran

Apakah ultah Anda dalam himpunan1?
1 3 5 7
9 11 13 15
17 19 21 23
25 27 29 31

Masukkan o untuk Tidak dan 1 Untuk Ya: 1
Apakah ultah Anda dalam himpunan2?
2 3 6 7
10 11 14 15
18 19 22 23
26 27 30 31

Masukkan o untuk Tidak dan 1 Untuk Ya: 0
Apakah ultah Anda dalam himpunan3?
4 5 6 7
12 13 14 15
20 21 22 23
28 29 30 31

Masukkan o untuk Tidak dan 1 Untuk Ya: 1
Apakah ultah Anda dalam himpunan4?
8 9 10 11
12 13 14 15
24 25 26 27
28 29 30 31

Masukkan o untuk Tidak dan 1 Untuk Ya: 1
Apakah ultah Anda dalam himpunan5?
16 17 18 19
20 21 22 23
24 25 26 27
28 29 30 31

Masukkan o untuk Tidak dan 1 Untuk Ya: 0
Hari Ultah Anda adalah 13

Karena dapatNilai adalah suatu metode statik, Anda tidak perlu menciptakan suatu objek untuk memanggilnya. Metode TebakTanggal.dapatNilai(i, j, k) mengembalikan tanggal pada baris j dan kolom k dalam himpunan i.


Kelas TebakTanggal dapat diimplementasikan pada kode10.10.

Kode10.10 TebakTanggal.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class TebakTanggal {
  private final static int[][][] tanggal = {
    {{ 1, 3, 5, 7},
     { 9, 11, 13, 15},
     {17, 19, 21, 23},
     {25, 27, 29, 31}},
    {{ 2, 3, 6, 7},
     {10, 11, 14, 15},
     {18, 19, 22, 23},
     {26, 27, 30, 31}},
    {{ 4, 5, 6, 7},
     {12, 13, 14, 15},
     {20, 21, 22, 23},
     {28, 29, 30, 31}},
    {{ 8, 9, 10, 11},
     {12, 13, 14, 15},
     {24, 25, 26, 27},
     {28, 29, 30, 31}},
    {{16, 17, 18, 19},
     {20, 21, 22, 23},
     {24, 25, 26, 27},
     {28, 29, 30, 31}}};

  /** Mencegah pengguna dalam menciptakan objek TebakTanggal */
  private TebakTanggal() {
  }

  /** Mengembalikan suatu tanggal pada baris dan kolom tertentu dari himpunan yang diberikan */
  public static int dapatNilai(int noHimp, int k, int j) {
    return tanggal[noHimp][k][j];
  }
}




No comments:

Post a Comment