Pemrograman
Generik
7.1 Pengantar
Bab ini mendiskusikan pemrograman generik,
yang memberikan cara-cara dalam menciptakan model-model umum dalam pemrograman.
Metode generik memampukan Anda untuk menetapkan, dengan satu deklarasi metode,
sehimpunan metode yang saling berelasi. Kelas generik memampukan Anda untuk
menetapkan, dengan satu deklarasi kelas, sehimpunan kelas yang saling berelasi.
Sama juga, antarmuka generik memampukan Anda untuk menetapkan, dengan satu
deklarasi antarmuka, sehimpunan antarmuka yang saling berelasi. Sampai sejauh ini,
buku ini telah menggunakan tipe generik List dan Dictionary.
Anda dapat menuliskan sebuah metode
generik untuk mengurutkan array yang memuat objek-objek, kemudian memanggil
metode generik secara terpisah pada array int,
array double, array string, dan seterusnya, untuk
mengurutkan setiap array dengan tipe-tipe yang berbeda. Kompiler melakukan
pemeriksaan tipe untuk memastikan bahwa array yang dilewatkan kepada metode
pengurut hanya memuat elemen-elemen dengan tipe yang sesuai. Anda dapat menulis
sebuah kelas generik Tumpukan yang
memanipulasi setumpuk objek-objek, kemudian menginstansiasi objek-objek Tumpukan dengan tumpukan int, tumpukan double, tumpukan string,
dan seterusnya. Kompiler melakukan pemeriksaan tipe untuk memastikan bahwa Tumpukan hanya memuat elemen-elemen
dengan tipe yang sesuai.
7.2
Motivasi Menggunakan Metode Generik
Metode-metode teroverload seringkali dipakai untuk melakukan operasi-operasi yang
sama pada data dengan tipe-tipe yang berbeda. Untuk memahami motivasi
penggunaan metode generik, akan diberiksan sebuah contoh (Gambar 7.1) yang
memuat tiga metode TampilArray teroverload (baris 23-29, baris 32-38), dan
baris 41-47). Ketiga metode ini menampilkan elemen-elemen sebuah array int, array double, dan array char. Selanjutnya,
nanti akan diimplementasikan-ulang program ini menggunakan satu metode generik.
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
|
//
Gambar 7.1: Metode2Teroverload.cs
//
Menggunakan metode-metode teroverload untuk
menampilkan array-array berbeda tipe.
using
System;
class
Metode2Teroverload
{
static
void Main( string[] args )
{
// menciptakan array int, double, dan
char
int[]
intArray = { 1, 2, 3, 4, 5, 6 };
double[]
doubleArray = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };
char[]
charArray = { 'H', 'A', 'L', 'L', 'O' };
Console.WriteLine( "Array intArray memuat:" );
TampilArray(
intArray ); // melewatkan sebuah argumen array int
Console.WriteLine("Array doubleArray memuat:");
TampilArray(doubleArray);
// melewatkan sebuah argumen array double
Console.WriteLine("Array charArray memuat:");
TampilArray(charArray);
// melewatkan sebuah argumen array char
} // akhir Main
// menampilkan array int
private static void TampilArray( int[] arrayMasukan )
{
foreach ( int elemen in
arrayMasukan )
Console.Write(
elemen + " " );
Console.WriteLine(
"\n" );
} // akhir metode TampilArray
// menampilkan array array
private static void TampilArray( double[] arrayMasukan )
{
foreach ( double elemen in
arrayMasukan )
Console.Write(
elemen + " " );
Console.WriteLine(
"\n" );
} // akhir metode TampilArray
// menampilkan array char
private static void TampilArray( char[] arrayMasukan )
{
foreach ( char elemen in
arrayMasukan )
Console.Write(
elemen + " " );
Console.WriteLine(
"\n" );
} // akhir metode TampilArray
} // akhir kelas Metode2Teroverload
|
Array intArray memuat:
1 2 3 4 5 6
Array doubleArray memuat:
1.1 2.2 3.3 4.4 5.5 6.6 7.7
Array charArray memuat:
H A L L O
|
Program memulai dengan mendeklarasikan
dan menginisialisasi tiga array, yaitu array int intArray
enam-elemen (baris 11), array double doubleArray tujuh-elemen (baris 11), dan array char charArray
lima-elemen (baris 12). Kemudian, baris 14-19 menampilkan ketiga array itu.
Ketika kompiler menjumpai sebuah
pemanggilan metode, ia akan mencoba mencari sebuah deklarasi metode yang
memiliki nama sama dan parameter-parameter yang cocok dengan tipe-tipe argumen
pada pemanggilan metode.
Pada contoh ini, setiap pemanggilan TampiArray cocok dengan salah satu
deklarasi metode TampilArray.
Sebagai contoh, baris 15 memanggil TampilArray
dengan intArray sebagai argumennya.
Pada saat kompilasi, kompiler menentukan tipe argumen intArray (misalnya, int[ ]),
yang mencoba untuk menemukan sebuah metode yang bernama TampilArray yang menetapkan suatu parameter int[ ] (ditemukan pada baris 23-29) dan menetapkan pemanggilan
terhadap metode tersebut. Sama halnya, ketika kompiler menjumpai pemanggilan TampilArray pada baris 17, ia
menentukan tipe argume doubleArray
(misalnya, double[ ]), kemudian
mencoba mencari sebuah metode dengan nama TampilArray
yang memiliki satu parameter double[ ]
(ditemukan pada baris 32-38) dan menetapkan pemanggilan terhadap metode
tersebut. Terakhir, ketika kompiler menjumpai pemanggilan array TampilArray pada baris 19, ia
menentukan tipe argumen charArray
(misalnya, char[ ]), kemudian mencoba
mencari lokasi sebuah metode dengan nama TampilArray
yang memiliki satu parameter char[ ]
(ditemukan pada baris 41-47) dan menetapkan pemanggilan terhadap metode
tersebut.
Anda bisa mencermati setiap metode TampilArray. Perhatikan bahwa tipe
elemen array (int, double, atau char) muncul pada dua lokasi di dalam setiap metode, yaitu di header metode (baris 23, 32, dan 41) dan
header statemen foreach (baris 25, 34, dan 43). Jika Anda mengganti tipe-tipe
elemen pada tiap metode dengan sebuah nama generik (seperti T untuk “type”), maka ketiga metode akan menjadi seperti pada Gambar 7.2. Tampak
bahwa Anda dapat mengganti tipe elemen array pada tiap metode dengan satu
“parameter tipe generik”, kemudian Anda hanya perlu mendeklarasikan satu metode
TampilArray yang menampilkan
elemen-elemen dari sembarang array.
Metode pada Gambar 7.2 tidak dapat dikompilasi, karena sintaksnya tidak tepat.
Anda mendeklarasikan sebuah metode TampilArray
generik yang sintaks yang tepat pada Gambar 7.3.
1
2
3
4
5
6
7
|
// Gambar 7.2: Deklarasi sebuah metode generik
private static void TampilArray(
T[] arrayMasukan )
{
foreach ( T elemen in arrayMasukan )
Console.Write( elemen + "
" );
Console.WriteLine( "\n" );
} // akhir metode TampilArray
|
7.3
Implementasi Metode Generik
Jika operasi-operasi yang dilakukan
oleh beberapa metode teroverload
identik untuk tiap tipe argumen, maka metode-metode teroverload tersebut dapat dikode dengan lebih kompak menggunakan
metode generik. Anda dapat menuliskan sebuah deklarasi metode generik yang
dapat dipanggil dengan argumen-argumen berbeda tipe. Berdasarkan tipe-tipe
argumen yang dilewatkan kepada metode generik, kompiler akan menangani setiap
pemanggilan metode secara tepat.
Gambar 7.3 mengimplementasikan-ulang
aplikasi pada Gambar 7.1 menggunakan sebuah metode TampilArray generik (baris 24-30). Perhatikan bahwa
pemanggilan-pemanggilan metode TampilArray pada baris 6, 18, dan 20 identik
dengan kode pada Gambar 7.1, yang menampilkan dua aplikasi identik dan kode
pada Gambar 7.3 merupakan 17 baris lebih pendek dari kode pada Gambar 7.1.
Seperti diilustrasikan pada Gambar 7.3, pemrograman generik memampukan Anda
untuk menciptakan dan menguji kode sekali saja, kemudian menggunakan-kembali
kode tersebut untuk pelbagai tipe data. Ini mendemonstrasikan kekuatan generik
yang mengesankan.
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
|
//
Gambar 7.3: MetodeGenerik.cs
//
Menggunakan metode-metode teroverload untuk
menampilkan array-array pelbagai tipe.
using
System;
using
System.Collections.Generic;
class
MetodeGenerik
{
static
void Main(string[] args)
{
// menciptakan array int, double, dan
char
int[]
intArray = { 1, 2, 3, 4, 5, 6 };
double[]
doubleArray = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };
char[]
charArray = { 'H', 'A', 'L', 'L', 'O' };
Console.WriteLine("Array intArray memuat:");
TampilArray(intArray);
// melewatkan sebuah argumen array int
Console.WriteLine("Array doubleArray memuat:");
TampilArray(doubleArray);
// melewatkan sebuah argumen array double
Console.WriteLine("Array charArray memuat:");
TampilArray(charArray);
// melewatkan sebuah argumen array char
} // akhir Main
// menampilkan array dengan semua tipe
private static void TampilArray<T>(T[]
arrayMasukan)
{
foreach (T elemen in arrayMasukan)
Console.Write(elemen
+ " ");
Console.WriteLine("\n");
} // akhir metode TampilArray
} // akhir kelas MetodeGenerik
|
Array intArray memuat:
1 2 3 4 5 6
Array doubleArray memuat:
1.1 2.2 3.3 4.4 5.5 6.6 7.7
Array charArray memuat:
H A L L O
|
Baris 24 memulai deklarasi dari metode TampilArray. Semua deklarasi metode
generik memiliki daftar parameter-tipe yang diapit oleh sepasang kurung siku (<T> pada contoh ini) yang berada
setelah nama metode. Setiap daftar parameter-tipe dapat memuat satu atau lebih
parameter tipe, yang dipisahkan dengan koma. Parameter tipe merupakan sebuah
pengenal yang dipakai menggantikan nama tipe aktual. Parameter tipe dapat
digunakan untuk mendeklarasikan tipe nilai balik, tipe parameter, dan tipe
variabel lokal di dalam deklarasi metode generik; parameter tipe berperan
sebagai placeholder untuk argumen
tipe yang merepresentasikan tipe data yang akan dilewatkan kepada metode
generik.
Tubuh metode generik dideklarasikan
seperti tubuh metode lainnya. Sebagai contoh, baris 26 mendeklarasikan elemen
pada statemen foreach sebagai tipe
T, yang cocok dengan parameter tipe (T) yang dideklarasikan pada baris 24.
Selain itu, sebuah parameter tipe hanya dapat dideklarasikan sekali pada daftar
parameter-tipe tetapi dapat muncul lebih dari sekali pada daftar parameter
metode.
Daftar parameter-tipe pada metode TampilArray (baris 24) mendeklarasikan
parameter tipe T sebagai placeholder untuk
tipe elemen-array yang akan ditampilkan TampilAray.
Perhatikan bahwa T muncul pada daftar parameter sebagai tipe elemen-array
(baris 24). Header statemen foreach (baris 26) juga menggunakan T
sebagai tipe elemen. Ada dua lokasi
yang sama dimana metode-metode TampilArray
teroverload dari Gambar 7.1
menetapkan tipe elemen int, double, atau char.
Sama seperti pada Gambar 7.1, program
pada Gambar 7.3 memulai dengan mendeklarasikan dan menginisialisasi sebuah
array int intArray enam-elemen
(baris 11), sebuah array double doubleArray tujuh-elemen (baris 12),
dan sebuah array char charArray lima-elemen (baris 13).
Kemudian tiap array ditampilkan dengan memanggil TampilArray (baris 16, 18, dan 20), sekali dengan argumen intArray, sekali dengan argumen doubleArray, dan sekali dengan argumen charArray.
Pada kasus pada baris 16, kompiler
menentukan bahwa kecocokan terbaik terjadi jika parameter tipe T pada baris 24 dan 26 dari deklarasi
metode TampilArray diganti dengan
tipe elemen pada argumen intArray
(yaitu, int) pada pemanggilan
metode. Kemudian, kompiler menetapkan sebuah pemanggilan terhadap TampilArray dengan int sebagai argumen
tipe untuk parameter tipe T. Ini
dikenal dengan penyimpulan-tipe. Proses yang sama diulangi untuk
pemanggilan-pemanggilan terhadap metode TampilArray
pada baris 18 dan 20.
Anda juga dapat menggunakan argumen
tipe eksplisit untuk mengindikasikan bahwa tipe persis apa yang harus dipakai
untuk memanggil sebuah fungsi generik. Sebagai contoh, baris 16 dapat
dituliskan sebagai
TampilArray<
int >( intArray ); // melewatkan sebuah argumen int
Pemanggilan metode tersebut secara
eksplisit menyediakan argumen tipe (int)
yang dipakai untuk mengganti parameter tipe T pada baris 24 dan 26 pada deklarasi metode TampilArray.
Untuk tiap variabel yang dideklarasikan
dengan sebuah parameter tipe, kompiler juga menentukan apakah operasi-operasi
yang dilakukan terhadap variabel semacam itu diijinkan untuk semua tipe yang
diwakili oleh parameter tipe. Satu-satunya operasi pada elemen-elemen array
dalam contoh ini adalah untuk menampilkan representasi string atas elemen-elemen tersebut. Baris 27 melakukan konversi boxing implisit untuk setiap elemen
array tipe-nilai dan untuk pemanggilan ToString
implisit pada tiap elemen array. Karena semua objek dapat memiliki metode ToString, kompiler menyimpulkan bahwa
baris 27 merupakan operasi yang valid dilakukan terhadap setiap elemen array.
Dengan mendeklarasikan TampilArray sebagai sebuah metode
generik pada Gambar 7.3, Anda dapat mengeliminasi kebutuhan akan metode-metode
teroverload pada Gambar 7.1,
menghemat 17 baris kode dan menciptakan sebuah metode yang dapat didaur-ulang
yang dapat menampilkan representasi string
atas tiap elemen pada semabarang array satu-dimensi, tidak hanya untuk array int, array double, atau array char.
7.4
Kekangan Tipe
Pada bagian ini, akan disajikan sebuah
metode Maksimum generik yang
menentukan menghasilkan elemen terbesar dari tiga argumennya (ketiganya dengan
tipe sama). Metode generik pada contoh ini menggunakan parameter tipe untuk
mendeklarasikan tipe nilai balik dan tiap parameter metode. Normalnya, ketika
membandingkan nilai-nilai untuk menentukan mana yang lebih besar, Anda perlu
menggunakan operator <. Namun,
operator ini tidak dioverload agar
bisa digunakan setiap tipe pada Pustaka Kelas .NET Framework. Kode generik tidak dapat menggunakan operasi ini. Jadi,
ekspresi seperti variabel1 <
variabel2 tidak diijinkan kecuali jika kompiler dapat memastikan bahwa
operator < disediakan untuk
setiap tipe yang akan digunakan pada kode generik. Sama halnya, Anda tidak
dapat memanggil sebuah metode pada sebuah variabel tipe-generik kecuali jika
kompiler dapat memastikan bahwa semua tipe yang akan digunakan pada kode
generik tersebut mendukung metode itu.
Antarmuka IComparable<T>
Adalah memungkinkan untuk membandingkan
dua objek bertipe sama jika tipe itu mengimplementasikan antarmuka generik IComparable<T> (dari namespace System). Keuntungan dari pengimplementasian antarmuka IComparable<T> adalah bahwa
objek-objek IComparable<T>
dapat dipakai dengan metode pengurutan dan metode pencarian dari kelas-kelas
pada namespace System.Collections.Generic. Setiap struktur pada Pustaka Kelas .NET
yang terkait dengan setiap tipe sederhana semuanya mengimplementasikan
antarmuka ini. Sebagai contoh, struktur untuk tipe sederhana double adalah Double dan struktur untuk tipe sederhana int adalah Int32. Kedua Double dan Int32 mengimplementasikan antarmukan IComparable<T>. Tipe-tipe yang mengimplementasikan antarmuka IComparable<T> harus
mendeklarasikan sebuah metode CompareTo
untuk membandingkan objek-objek. Sebagai contoh, jika Anda memiliki dua int, int1 dan int2, maka
keduanya dapat dibandingkan dengan ekspresi:
int1.CompareTo(
int2 )
Metode CompareTo menghasilkan nilai balik 0 jika kedua objek sama, nilai
balik negatif jika int1 lebih kecil
daripada int2, atau nilai balik
positif jika int1 lebih besar
daripada int2. Adalah tanggung-jawab
programer yang mendeklarasikan sebuah tipe yang mengimplementasikan antarmuka IComparable<T> untuk
mendefinisikan metode CompareTo
sehingga ia membandingkan isi dari dua objek dengan tipe tersebut dan
menghasilkan hasil yang diinginkan.
Menetapkan Kekangan Tipe
Meskipun objek-objek IComparable dapat dibandingkan,
objek-objek itu tidak dapat digunakan pada kode generik secara default, karena
tidak semua tipe mengimplementasikan IComparable<T>.
Namun, Anda dapat membatasi tipe-tipe yang dapat dipakai pada metode atau kelas
generik untuk memastikan bahwa tipe-tipe itu memenuhi beberapa persyaratan.
Fitur ini dikenal sebagai pengekangan tipe, untuk membatasi tipe argumen yang
disediakan bagi parameter tipe tertentu. Gambar 7.4 mendeklarasikan metode Maksimum (baris 20-34) dengan sebuah
kekangan tipe yang mensyaratkan setiap argumen pada metode harus bertipe IComparable<T>. Pembatasan ini
penting, karena tidak semua objek dapat dibandingkan. Namun, semua objek IComparable<T> dijamin untuk
memiliki sebuah metode CompareTo
yang dapat dipakai pada metode Maksimum
untuk menentukan argumen terbesar dari ketiga argumen yang ada.
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
|
//
Gambar 7.4: UjiMaksimum.cs
//
Metode Maksimum generik menghasilkan yang terbesar dari ketiga objek.
using
System;
class
UjiMaksimum
{
public
static void Main( string[] args )
{
Console.WriteLine( "Maksimum dari {0}, {1} dan {2} adalah {3}\n",
3, 4, 5, Maksimum(3, 4, 5));
Console.WriteLine("Maksimum dari {0}, {1} dan {2} adalah {3}\n",
6.6, 8.8, 7.7, Maksimum(6.6, 8.8,
7.7));
Console.WriteLine("Maksimum dari {0}, {1} dan {2} adalah {3}\n",
"mangga", "apel",
"jeruk",
Maksimum("mangga", "apel", "jeruk"));
} // akhir Main
// fungsi generik menentukan yang
terbesar dari
// objek-objek IComparable
private
static T Maksimum<T>(T x, T
y, T z)
where
T : IComparable< T >
{
T maks = x; // mengasumsikan x
awalnya terbesar
// membandingkan y dengan maks
if
( y.CompareTo( maks ) > 0 )
maks = y; // y terbesar sejauh
ini
// membandingkan z dengan maks
if
( z.CompareTo( maks ) > 0 )
maks = z; // z adalah terbesar
return
maks; // menghasilka objek terbesar
} // akhir metode Maksimum
} // akhir kelas UjiMaksimum
|
Maksimum dari 3, 4 dan 5 adalah 5
Maksimum dari 6.6, 8.8 dan 7.7 adalah 8.8
Maksimum dari mangga, apel dan jeruk adalah mangga
|
Metode Maksimum generik menggunakan parameter tipe T sebagai tipe nilai balik dari metode itu (baris 20), sebagai tipe
dari parameter-parameter metode x, y, dan z (baris 20), dan sebagai tipe dari variabel lokal maks (baris 23). Klausa where pada metode Maksimum generik (setelah daftar parameter pada baris 21)
menetapkan kekangan tipe untuk parameter tipe T. Pada kasus ini, klausa where
T : IComparable<T> mengindikasikan bahwa metode ini memerlukan
argumen tipe untuk mengimplementasikan antarmuka IComparable<T>. Jika tidak ada kekangan tipe yang ditetapkan,
maka kekangan tipe default adalah object.
Metode Maksimum mengasumsikan bahwa argumen pertamanya (x) adalah yang terbesar dan
menugaskannya kepada variabel lokal maks
(baris 23). Selanjutnya, statemen if
pada baris 26-27 menentukan apakah y
lebih besar dari maks. Kondisi
tersebut memanggil metode CompareTo
pada y dengan ekspresi y.CompareTo(maks). Jika y lebih besar dari maks, maka y ditugaskan
kepada variabel maks (baris 27).
Sama halnya, statemen pada baris 30-31 menentukan apakah z lebih besar dari maks. Jika ya, maka baris 31 menugaskan
z kepada maks. Kemudian, baris 33 menghasilkan maks dan memberikannya kepada pemanggil.
Pada Main (baris 7-16), baris 10 memangil Maksimum dengan integer 3, 4, dan 5. Metode Maksimum generik cocok dengan pemanggilan ini, tetapi argumennya
harus mengimplementasikan antarmuka IComparable<T>.
untuk memastikan bahwa argumen-argumen itu dapat dibandingkan. Tipe int merupakan sebuah sinonim untuk struct Int32, yang mengimplementasikan
antarmuka IComparable<int>.
Jadi, int (dan tipe-tipe sederhana
lainnya) merupakan argumen yang valid untuk metode Maksimum.
Baris 12 melewatkan ketiga argumen double kepada Maksimum. Lagi, ini diijinkan karena double merupakan sebuah
sinonim untuk struct Double, yang
mengimplementasikan antarmuka IComparable<double>.
Baris 15 melewatkan tiga string
kepada Maksimum, yang juga merupakan
objek-objek IComparable<string>.
7.5
Kelas Generik
Konsep sebuah struktur data (misalnya,
tumpukan) yang memuat elemen-elemen data dapat dipahami secara bebas tanpa
dipengaruhi oleh tipe elemen yang dimanipulasinya. Sebuah kelas generik
menyediakan beberapa cara dalam menjelaskan suatu kelas dengan aspek
bebas-tipe. Anda kemudian dapat menginstansiasi versi tipe spesifik dari kelas
generik. Kapabilitas ini merupakan peluang bagi pendaur-ulangan kode.
Dengan kelas generik, Anda dapat
menggunakan notasi sederhana dan singkat untuk mengindikasikan tipe aktual yang
dipakai dalam menggantikan parameter tipe pada kelas. Pada saat kompilasi,
kompiler memastikan keamanan tipe pada kode Anda dan mengganti parameter tipe
dengan argumen tipe agar kode klien dapat berinteraksi dengan kelas generik
tersebut.
Satu kelas Tumpukan generik, misalnya, dapat dipakai sebagai dasar untuk
menciptakan banyak kelas Tumpukan
lain (misalnya, Tumpukan dari double, Tumpukan dari int, Tumpukan dari char, Tumpukan dari Karyawan, dan lainnya). Gambar 7.5 menyajikan deklarasi kelas Tumpukan generik. Parameter tipe T merepresentasikan tipe elemen yang
akan dimanipulasi oleh Tumpukan.
Sama seperti metode generik, daftar parameter-tipe pada sebuah kelas generik
dapat memuat satu atau lebih parameter tipe (yang masing-masing dipisahkan
dengan koma). Parameter tipe T
dipakai di keseluruhan deklarasi kelas Tumpukan
(Gambar 7.5) untuk merepresentasikan tipe elemen. Kelas Tumpukan mendeklarasikan variabel elemen2 sebagai sebuah array bertipe T (baris 8). Array ini (diciptakan pada baris 21) akan menyimpan
elemen-elemen Tumpukan.
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
|
// Gambar 7.5: Tumpukan.cs
// Kelas Tumpukan generik.
using System;
class
Tumpukan< T >
{
private int atas; // lokasi dari elemen atas
private T[]
elemen2; // array yang memuat elemen-elemen tumpukan
// konstruktor tanpa-parameter menciptakan
tumpukan dengan ukuran default
public Tumpukan()
: this( 10 ) // ukuran
tumpukan default
{
// konstruktor kosong;
} // akhir konstruktor Tumpukan
// konstruktor menciptakan sebuah tumpukan
dengan jumlah elemen tertentu
public Tumpukan( int ukuranTumpukan )
{
if (ukuranTumpukan > 0)
// memvalidasi ukuranTumpukan
elemen2 = new T[ukuranTumpukan]; // menciptakan ukuranTumpukan elemen
else
throw new ArgumentException( "Ukuran Tumpukan harus positif." );
atas = -1; // tumpukan awalnya kosong
} // akhir konstruktor tumpukan
// menempatkan elemen ke atas tumpukan; jika tidak berhasil,
// akan melemparkan eksepsi TumpukanPenuhException
public void Push( T nilaiPush )
{
if ( atas == elemen2.Length
- 1 ) // tumpukan penuh
throw new
TumpukanPenuhException( string.Format(
"Tumpukan penuh, tidak bisa
menempatkan {0} ke atas tumpukan", nilaiPush ) );
++atas; // menginkremen atas
elemen2[ atas ] = nilaiPush; // menempatkan
nilaiPush ke atas tumpukan
} // akhir metode Push
// menghasilkan elemen atas jika tidak kosong,
// jika kosong, melempar eksepsi TumpukanKosongException
public T Pop()
{
if ( atas == -1 ) //
tumpukan kosong
throw new TumpukanKosongException("Tumpukan kosong, tidak bisa
operasi Pop");
--atas; // mendekreman atas
return elemen2[ atas + 1 ];
// menghasilkan nilai di atas tumpukan
} // akhir metode Pop
} // akhir kelas Tumpukan
|
Kelas Tumpukan memiliki dua konstruktor. Konstruktor tanpa-parameter
(baris 11-15) melewatkan ukuran tumpukan default (10) kepada konstruktor
satu-argumen, menggunakan sintaks this
(baris 12) untuk memanggil konstruktor lain pada kelas yang sama. Konstruktor
satu-argumen (baris 18-26) memvalidasi argumen ukuranTumpukan dan menciptakan sebuah array dengan ukuranTumpukan yang ditetapkan (jika
lebih besar dari 0) atau melemparkan sebuah eksepsi (jika lebih kecil dari 0).
Metode Push (baris 30-38) pertama-tama menentukan apakah yang dilakukan
adalah mencoba untuk menempatkan sebuah elemen ke atas Tumpukan yang penuh. Jika ya, baris 33-34 akan melemparkan sebuah
eksepsi TumpukanPenuhException
(dideklarasikan pada Gambar 7.6). Jika Tumpukan
tidak penuh, baris 36 akan menginkremen kounter atas untuk mengindikasikan posisi atas yang baru, dan baris 37
menempatkan argumen pada lokasi itu di dalam array elemen2.
Metode Pop (baris 42-49) pertama-tama menentukan apakah yang dilakukan
adalah mencoba untuk menempatkan sebuah elemen ke atas Tumpukan yang penuh. Jika ya, baris 45 akan melemparkan sebuah
eksepsi TumpukanKosongException
(dideklarasikan pada Gambar 7.7). Sebaliknya, baris 47 akan mendekremen kounter
atas untuk mengindikasikan posisi atas yang baru, dan baris 48 menghasilkan
elemen atas yang asli pada Tumpukan.
Kelas TumpukanPenuhException (Gambar 7.6) dan TumpukanKosongException (Gambar 7.7) masing-masing menyediakan
sebuah konstruktor tanpa-parameter, sebuah konstruktor satu-argumen, dan sebuah
konstruktor dua-argumen untuk menciptakan sebuah eksepsi baru menggunakan kelas
eksepsi yang sudah ada. Konstruktor tanpa-parameter menetapkan pesan error
default sedangkan dua konstruktor yang lain menetapkan pesan error yang dapat
dimodifikasi.
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
|
// Gambar 7.6:
TumpukanPenuhException.cs
// TumpukanPenuhException
mengindikasikan bahwa tumpukan penuh.
using System;
class
TumpukanPenuhException : Exception
{
// konstruktor tanpa-parameter
public
TumpukanPenuhException() : base(
"Tumpukan penuh" )
{
// konstruktor kosong
} // akhir konstruktor TumpukanPenuhException
// konstruktor satu-parameter
public
TumpukanPenuhException( string eksepsi ) : base( eksepsi )
{
// konstruktor kosong
} // akhir konstruktor TumpukanPenuhException
// konstruktor dua-parameter
public
TumpukanPenuhException(string
eksepsi, Exception inner)
: base(eksepsi, inner)
{
// konstruktor kosong
} // akhir konstruktor TumpukanPenuhException
} // akhir kelas TumpukanPenuhException
|
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
|
//
Gambar 7.7: TumpukanKosongException.cs
//
TumpukanKosongException mengindikasikan bahwa tumpukan kosong.
using
System;
class
TumpukanKosongException : Exception
{
// konstruktor tanpa-parameter
public
TumpukanKosongException() : base("Tumpukan kosong")
{
// konstruktor kosong
} // akhir konstruktor
TumpukanKosongException
// konstruktor satu-parameter
public
TumpukanKosongException(string
eksepsi) : base(eksepsi)
{
// konstruktor kosong
} // akhir konstruktor
TumpukanKosongException
// konstruktor dua-parameter
public
TumpukanKosongException(string
eksepsi, Exception inner)
: base(eksepsi, inner)
{
// konstruktor kosong
} // akhir konstruktor TumpukanKosongException
} //
akhir kelas TumpukanKosongException
|
Sekarang, akan disajikan sebuah
aplikasi (Gambar 7.8) yang menggunakan kelas Tumpukan generik. Baris 13-14 mendeklarasikan variabel-variabel
bertipe Tumpukan<double> dan Tumpukan<int>. Tipe double dan
int merupakan argumen tipe pada Tumpukan. Kompiler akan mengganti
parameter-parameter tipe pada kelas generik sehingga ia dapat melakukan
pemeriksaan tipe. Metode Main
menginstansiasi objek-objek tumpukanDouble
berukuran 5 (baris 18) dan tumpukanInt
berukuran 10 (baris 19), kemudian memanggil metode UjiPushDouble (baris 28-48), UjiPopDouble
(baris 51-73), UjiPushInt (baris
76-96), dan UjiPopInt (baris 99-121)
untuk memanipulasi dua Tumpukan pada
contoh ini.
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
// Gambar 7.8: UjiTumpukan.cs
// Menguji kelas Tumpukan generik.
using System;
class UjiTumpukan
{
// menciptakan array double dan array int
private static double[] elemen2Double =
new double[]{ 1.1, 2.2, 3.3, 4.4, 5.5, 6.6 };
private static int[] elemen2Int =
new int[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
private static Tumpukan< double
> tumpukanDouble; // menyimpan objek-objek double
private static Tumpukan<int>
tumpukanInt; // menyimpan objek-objek int
public static void Main(
string[] args )
{
tumpukanDouble = new
Tumpukan<double>(5); //
tumpukan double
tumpukanInt = new
Tumpukan<int>(10); //
tumpukan int
UjiPushDouble(); // menempatkan double pada tumpukanDouble
UjiPopDouble(); // menghapus double dari tumpukanDouble
UjiPushInt(); // menempatkan int pada tumpukanInt
UjiPopInt(); // menghapus int dari tumpukanInt
} // akhir Main
// menguji metode Push dengan tumpukanDouble
private static void UjiPushDouble()
{
// menempatkan elemen-elemen ke atas tumpukan
try
{
Console.WriteLine("\nMenempatkan elemen-elemen ke atas
tumpukanDouble");
// menempatkan elemen-elemen ke
atas tumpukan
foreach ( var elemen in elemen2Double )
{
Console.Write( "{0:F1}
", elemen );
tumpukanDouble.Push( elemen
); // menempatkan ke atas tumpukanDouble
} // akhir foreach
} // akhir try
catch (
TumpukanPenuhException eksepsi )
{
Console.Error.WriteLine();
Console.Error.WriteLine( "Pesan: " + eksepsi.Message );
Console.Error.WriteLine(
eksepsi.StackTrace );
} // akhir catch
} // akhir metode UjiPushDouble
// menguji metode Pop dengan tumpukanDouble
private static void UjiPopDouble()
{
// menghapus elemen-elemen dari tumpukan
try
{
Console.WriteLine("\nMenghapus elemen-elemen dari
tumpukanDouble");
double nilaiPop; // menyimpan elemen yang dihapus dari tumpukan
// menghapus semua elemen dari
tumpukan
while ( true )
{
nilaiPop =
tumpukanDouble.Pop(); // menghapus dari tumpukanDouble
Console.Write( "{0:F1}
", nilaiPop );
} // akhir while
} // akhir try
catch (
TumpukanKosongException eksepsi )
{
Console.Error.WriteLine();
Console.Error.WriteLine( "Pesan: " + eksepsi.Message );
Console.Error.WriteLine(
eksepsi.StackTrace );
} // akhir catch
} // akhir metode UjiPopDouble
// menguji metode Push dengan tumpukanInt
private static void UjiPushInt()
{
// menempatkan elemen-elemen ke atas tumpukan
try
{
Console.WriteLine( "\nMenempatkan elemen-elemen ke atas
tumpukanInt" );
// menempatkan elemen-elemen ke
atas tumpukan
foreach ( var elemen in elemen2Int )
{
Console.Write( "{0}
", elemen );
tumpukanInt.Push( elemen );
// menempatkan ke atas tumpukanInt
} // akhir foreach
} // akhir try
catch (
TumpukanPenuhException eksepsi )
{
Console.Error.WriteLine();
Console.Error.WriteLine( "Pesan: " + eksepsi.Message );
Console.Error.WriteLine( eksepsi.StackTrace
);
} // akhir catch
} // akhir metode UjiPushInt
// menguji metode Pop dengan tumpukanInt
private static void UjiPopInt()
{
// menghapus elemen-elemen dari tumpukan
try
{
Console.WriteLine( "\nMenghapus elemen-elemen dari
tumpukanInt" );
int nilaiPop; // menyimpan elemen yang dihapus dari tumpukan
// menghapus semua elemen dari
tumpukan
while ( true )
{
nilaiPop = tumpukanInt.Pop();
// menghapus dari TumpukanInt
Console.Write( "{0}
", nilaiPop );
} // akhir while
} // akhir try
catch (
TumpukanKosongException eksepsi )
{
Console.Error.WriteLine();
Console.Error.WriteLine( "Pesan: " + eksepsi.Message );
Console.Error.WriteLine(
eksepsi.StackTrace );
} // akhir catch
} // akhir metode UjiPopInt
} // akhir kelas UjiTumpukan
|
Menempatkan elemen-elemen ke atas tumpukanDouble
1.1 2.2 3.3 4.4 5.5 6.6
Pesan: Tumpukan penuh, tidak bisa menempatkan 6.6 ke
atas tumpukan
at
Tumpukan`1.Push(T nilaiPush) in e:\Projects Visual C#\Tumpukan\
Tumpukan\Program.cs:line
33
at
UjiTumpukan.UjiPushDouble() in e:\Projects Visual C#\Tumpukan\
Tumpukan\UjiTumpukan.cs:line
39
Menghapus elemen-elemen dari tumpukanDouble
5.5 4.4 3.3 2.2 1.1
Pesan: Tumpukan kosong, tidak bisa melakukan operasi
Pop
at
Tumpukan`1.Pop() in e:\Projects Visual C#\Tumpukan\
Tumpukan\Program.cs:line
45
at
UjiTumpukan.UjiPopDouble() in e:\Projects Visual C#\Tumpukan\
Tumpukan\UjiTumpukan.cs:line
63
Menempatkan elemen-elemen ke atas tumpukanInt
1 2 3 4 5 6 7 8 9 10 11
Pesan: Tumpukan penuh, tidak bisa menempatkan 11 ke
atas tumpukan
at
Tumpukan`1.Push(T nilaiPush) in e:\Projects Visual C#\Tumpukan\
Tumpukan\Program.cs:line
33
at
UjiTumpukan.UjiPushInt() in e:\Projects Visual C#\Tumpukan\
Tumpukan\UjiTumpukan.cs:line
87
Menghapus elemen-elemen dari tumpukanInt
10 9 8 7 6 5 4 3 2 1
Pesan: Tumpukan kosong, tidak bisa melakukan operasi
Pop
at
Tumpukan`1.Pop() in e:\Projects Visual C#\Tumpukan\
Tumpukan\Program.cs:line
45
at
UjiTumpukan.UjiPopInt() in e:\Projects Visual C#\Tumpukan\
Tumpukan\UjiTumpukan.cs:line
111
|
Metode UjiPushDouble (baris 28-48) memanggil metode Push untuk mengganti nilai-nilai double 1.1, 2.2, 3.3, 4.4 dan 5.5 yang disimpan
di dalam array elemen2Double ke atas
tumpukanDouble. Statemen foreach berhenti ketika program uji
mencoba untuk menempatkan (Push)
nilai keenam ke atas tumpukanDouble
(yang penuh, karena tumpukanDouble
hanya dapat menyimpan lima elemen). Pada kasus ini, metode ini melemparkan
sebuah eksepsi TumpukanPenuhException
(Gambar 7.6) untuk mengindikasikan bahwa Tumpukan
penuh. Baris 42-47 menangkap eksepsi ini dan menampilkan pesan dan informasi
jejak-tumpukan. Jejak tumpukan mengindikasikan eksepsi yang terjadi dan
menampilkan bahwa metode Push pada
kelas Tumpukan membangkitkan eksepsi
pada baris 36 dari file Tumpukan.cs
(Gambar 7.5). Jejak tersebut juga menunjukkan bahwa metode Push dipanggil oleh metode UjiPushDouble
dari kelas UjiTumpukan pada baris 39
dari file UjiTumpukan.cs. Informasi
ini memampukan Anda dalam menentukan metode-metode yang ada pada tumpukan
pemanggilan-metode pada saat eksepsi terjadi.
Metode UjiPopDouble (baris 51-73) memanggil metode Pop pada kelas Tumpukan
menggunakan sebuah loop while untuk
menghapus semua nilai dari tumpukan. Perhatikan pada keluaran bahwa nilai-nilai
yang dihapus dalam urutan LIFO (last-in, first-out). Ini merupakan karakteristik dari
struktur data tumpukan. Loop while
(baris 61-65) berlanjut sampai tumpukan kosong. Eksepsi TumpukanKosongException terjadi ketika program mencoba melakukan
operasi penghapus pada tumpukan kosong. Ini menyebabkan program melompat ke
blok catch (baris 67-72) dan
menangani eksepsi tersebut, sehingga program dapat melanjutkan eksekusi. Ketika
program uji mencoba melakukan operasi Pop
untuk menghapus nilai keenam, tumpukanDouble
telah kosong, sehingga metode Pop
melemparkan eksepsi TumpukanKosongException.
Metode UjiPushInt (baris 76-96) memanggil metode Push pada kelas Tumpukan
untuk menempatkan nilai-nilai ke atas tumpukanInt
sampai ia penuh. Metode UjiPopInt
(baris 99-121) memanggil metode Pop
pada kelas Tumpukan untuk menghapus
nilai-nilai dari tumpukanInt sampai
ia kosong. Sekali lagi, perhatikan bahwa nilai-nilai dihapus dari tumpukan
dalam tatanan LIFO.
Menciptakan Metode Generik untuk Menguji Kelas Tumpukan<T>
Perhatikan bahwa kode pada metode UjiPushDouble dan UjiPushInt hampir identik untuk menempatkan nilai-nilai ke atas Tumpukan<double> atau Tumpukan<int>. Sama halnya, kode
pada metode UjiPopDouble dan UjiPopInt hampir identik untuk
menghapus nilai-nilai dari atas Tumpukan<double>
atau Tumpukan<int>. Hal ini
menciptakan peluang untuk memanfaatkan metode generik. Gambar 7.9
mendeklarasikan metode UjiPush
(baris 33-54) untuk melakukan pekerjaan yang sama dengan UjiPushDouble dan UjiPushInt
pada Gambar 7.8. Sama halnya, Gambar 7.9 mendeklarasikan metode UjiPop (baris 57-79) untuk melakukan
pekerjaan yang sama dengan UjiPopDouble
dan UjiPopInt pada Gambar 7.8.
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
72
73
74
75
76
77
78
79
80
|
// Gambar 7.9:
UjiTumpukanMetodeGenerik.cs
// Menguji kelas Tumpukan generik.
using System;
using
System.Collections.Generic;
class
UjiTumpukanMetodeGenerik
{
// menciptakan array double dan array int
private static double[] elemen3Double =
new double[] { 1.1,
2.2, 3.3, 4.4, 5.5, 6.6 };
private static int[] elemen3Int =
new int[] { 1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11 };
private static Tumpukan<double> tumpukanDouble1; // menyimpan objek-objek double
private static Tumpukan<int> tumpukanInt1; // menyimpan objek-objek int
public static void
Main(string[] args)
{
tumpukanDouble1 = new Tumpukan<double>(5); // tumpukan double
tumpukanInt1 = new Tumpukan<int>(10); // tumpukan int
// menempatkan double-double pada
tumpukanDouble1
UjiPush("tumpukanDouble1",
tumpukanDouble1, elemen3Double);
// menghapus double-double dari
tumpukanDouble1
UjiPop("tumpukanDouble1",
tumpukanDouble1);
// menempatkan int-int pada
tumpukanInt1
UjiPush("tumpukanInt1", tumpukanInt1,
elemen3Int);
// menghapus int-int dari
tumpukanInt1
UjiPop("tumpukanInt1", tumpukanInt1);
} // akhir Main
// menguji metode Push
private static void
UjiPush<T>(string nama,
Tumpukan<T> tumpukan,
IEnumerable<T> elemen2)
{
// menempatkan elemen-elemen ke
atas tumpukan
try
{
Console.WriteLine("\nMenempatkan elemen-elemen ke atas
"
+ nama);
// menempatkan elemen-elemen
ke atas tumpukan
foreach (var elemen in elemen2)
{
Console.Write("{0}
", elemen);
tumpukan.Push(elemen); //
menempatkan ke atas tumpukan
} // akhir foreach
} // akhir try
catch (TumpukanPenuhException eksepsi)
{
Console.Error.WriteLine();
Console.Error.WriteLine("Pesan:
" + eksepsi.Message);
Console.Error.WriteLine(eksepsi.StackTrace);
} // akhir catch
} // akhir metode UjiPush
// menguji metode Pop dengan tumpukanDouble
private static void UjiPop<T>(string
nama, Tumpukan<T> tumpukan)
{
// menghapus elemen-elemen dari
tumpukan
try
{
Console.WriteLine("\nMenghapus elemen-elemen dari " + nama);
T nilaiPop; // menyimpan elemen yang dihapus dari tumpukan
// menghapus semua elemen
dari tumpukan
while (true)
{
nilaiPop =
tumpukan.Pop(); // menghapus dari tumpukan
Console.Write("{0}
", nilaiPop);
} // akhir while
} // akhir try
catch (TumpukanKosongException eksepsi)
{
Console.Error.WriteLine();
Console.Error.WriteLine("Pesan:
" + eksepsi.Message);
Console.Error.WriteLine(eksepsi.StackTrace);
} // akhir catch
} // akhir metode UjiPop
} // akhir kelas UjiTumpukanMetodeGenerik
|
Menempatkan elemen-elemen ke atas tumpukanDouble1
1.1 2.2 3.3 4.4 5.5 6.6
Pesan: Tumpukan penuh, tidak bisa menempatkan 6.6 ke
atas tumpukan
at
Tumpukan`1.Push(T nilaiPush) in e:\Projects Visual C#\Tumpukan\
Tumpukan\Program.cs:line
33
at
UjiTumpukanMetodeGenerik.UjiPush[T](String nama, Tumpukan`1 tumpukan,
IEnumerable`1
elemen2) in e:\Projects Visual C#\Tumpukan\
Tumpukan\UjiTumpukanMetodeGenerik.cs:line
45
Menghapus elemen-elemen dari tumpukanDouble1
5.5 4.4 3.3 2.2 1.1
Pesan: Tumpukan kosong, tidak bisa melakukan operasi
Pop
at
Tumpukan`1.Pop() in e:\Projects Visual C#\Tumpukan\
Tumpukan\Program.cs:line
45
at
UjiTumpukanMetodeGenerik.UjiPop[T](String nama, Tumpukan`1 tumpukan)
in e:\
Projects Visual C#\Tumpukan\Tumpukan\
UjiTumpukanMetodeGenerik.cs:line
69
Menempatkan elemen-elemen ke atas tumpukanInt1
1 2 3 4 5 6 7 8 9 10 11
Pesan: Tumpukan penuh, tidak bisa menempatkan 11 ke
atas tumpukan
at
Tumpukan`1.Push(T nilaiPush) in e:\Projects Visual C#\Tumpukan\
Tumpukan\Program.cs:line
33
at
UjiTumpukanMetodeGenerik.UjiPush[T](String nama, Tumpukan`1 tumpukan,
IEnumerable`1
elemen2) in e:\Projects Visual C#\Tumpukan\
Tumpukan\UjiTumpukanMetodeGenerik.cs:line
45
Menghapus elemen-elemen dari tumpukanInt1
10 9 8 7 6 5 4 3 2 1
Pesan: Tumpukan kosong, tidak bisa melakukan operasi
Pop
at
Tumpukan`1.Pop() in e:\Projects Visual C#\Tumpukan\
Tumpukan\Program.cs:line
45
at
UjiTumpukanMetodeGenerik.UjiPop[T](String nama, Tumpukan`1 tumpukan)
in
e:\Projects Visual C#\Tumpukan\Tumpukan\
UjiTumpukanMetodeGenerik.cs:line
69
|
Metode Main (baris 17-30) menciptakan Tumpukan<double>
pada baris 19 dan Tumpukan<int>
(baris 20). Baris 23-29 memanggil metode generik, UjiPush dan UjiPop,
untuk menguji objek-objek Tumpukan.
Metode UjiPush generik (baris 33-54) menggunakan parameter tipe T (ditetapkan pada baris 33) untuk
merepresentasikan tipe data yang disimpan di dalam Tumpukan. Metode generik itu mengambil tiga argumen, yaitu sebuah string yang merepresentasikan nama dari
objek Tumpukan, sebuah objek bertipe
Tumpukan<T>, dan sebuah IEnumerable<T> yang memuat
elemen-elemen yang akan ditempatkan ke atas Tumpukan<T>. Perhatikan bahwa kompiler menegakkan konsistensi
antara tipe dari Tumpukan dan
elemen-elemen yang akan ditempatkan ke atas Tumpukan ketika Push
dipanggil. Metode UjiPop generik
(baris 57-79) memerlukan dua argumen, yaitu sebuah string yang merepresentasikan nama dari objek Tumpukan dan sebuah objek bertipe Tumpukan<T>.
No comments:
Post a Comment