Saturday, December 24, 2016

Bab 9. Visual Basic .NET Belajar Dari Contoh



9. Pemrograman Berorientasi Objek: Polimorfisme







Pengantar

Diskusi tentang pemrograman berorientasi objek (PBO) pada bab terdahulu difokuskan pada salah satu komponen kunci, pewarisan. Pada bab ini, akan dilanjutkan untuk membahas PBO polimorfisme. Kedua pewarisan dan polimorfisme adalah komponen krusial dalam pengembangan perangkat-lunak yang kompleks. Polimorfisme memampukan Anda untuk menulis program yang dapat menangani berbagai varietas kelas yang berelasi dan memfasilitasi penambahan kelas dan kapabilitas baru ke dalam suatu sistem.

Dengan polimorfisme, dimungkinkan untuk merancang dan mengimplementasikan sistem yang mudah untuk diperluas atau dikembangkan. Program dapat memproses objek-objek dari semua kelas di dalam suatu hirarki kelas yang secara generik dipandang sebagai objek-objek dengan kelas basis yang sama. Di samping itu, kelas baru dapat ditambahkan dengan sedikit atau tanpa modifikasi terhadap program, sepanjang kelas baru tersebut adalah bagian dari hirarki pewarisan yang diproses secara generik oleh program. Satu-satunya bagian program yang perlu dimodifikasi untuk mengakomodasi kelas baru adalah komponen program yang memerlukan pengetahuan langsung tentang kelas baru yang ditambahkan programer ke dalam hirarki. Pada bab ini, akan didemonstrasikan dua hirarki kelas dan objek-objek dari kedua hirarki akan dimanipulasi secara polimorfik.


Konversi Objek-Kelas-Terderivasi Menjadi Objek-Kelas-Basis
Pada bab sebelumnya, telah diciptakan hirarki kelas titik-lingkaran, dimana kelas CLingkaran mewarisi kelas CTitik. Program yang memanipulasi objek-objek dari kedua kelas tersebut selalu menggunakan referensi CTitik untuk menunjuk ke objek CTitik dan referensi CLingkaran untuk menunjuk ke objek CLingkaran. Pada bagian ini, akan didiskusikan relasi antar kelas di dalam hirarki yang memampukan sebuah program untuk menugaskan objek kelas terderivasi kepada referensi kelas basis. Ini merupakan bagian fundamental dalam memproses objek secara polimorfik. Bagian ini juga akan mendiskusikan casting secara eksplisit antar tipe di dalam suatu hirarki kelas.

Objek suatu kelas terderivasi dapat diperlakukan seperti objek kelas basisnya. Ini memampukan berbagai manipulasi menarik. Sebagai contoh, program dapat menciptakan suatu array yang memuat beberapa referensi kelas basis yang menunjuk ke beberapa objek kelas terderivasi. Hal ini diijinkan meskipun objek kelas terderivasi memiliki tipe data yang berbeda. Namun, kebalikannya tidak berlaku, karena objek kelas basis bukanlah objek kelas terderivasinya. Sebagai contoh, objek CTitik bukanlah objek CLingkaran.

Contoh pada kode 9.1 – 9.3 mendemonstrasikan penugasan objek kelas terderivasi kepada referensi kelas basis dan menunjukkan bagaimana melakukan casting terhadap referensi kelas basis menjadi referensi kelas terderivasi. Kelas CTitik (kode 9.1), yang telah didiskusikan pada Bab 8, merepresentasikan sepasang koordinat x-y. Kelas CLingkaran (kode 9.2), yang juga telah didiskusikan pada Bab 8, merepresentasikan sebuah lingkaran dan mewarisi kelas CTitik. Setiap objek CLingkaran “adalah suatu” CTitik dan juga memiliki sebuah radius (yang direpresentasikan via variabel mRadius). Metode Luas akan dideklarasikan sebagai Overridable, sehingga kelas terderivasi (seperti kelas CSilinder) dapat menghitung luasnya sendiri. Kelas CUji (kode 9.3) mendemonstrasikan operasi penugasan dan casting.

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
' Kode 9.1: Titik.vb
' kelas CTitik merepresentasikan pasangan koordinat x-y.

Public Class CTitik

    ' koordinat titik
    Private mX, mY As Integer

    ' konstruktor default
    Public Sub New()

        ' pemanggilan implisit terhadap konstruktor Object terjadi di sini
        X = 0
        Y = 0
    End Sub ' New

    ' konstruktor
    Public Sub New(ByVal xNilai As Integer, _
        ByVal yNilai As Integer)

        ' pemanggilan implisit terhadap konstruktor Object terjadi di sini
        X = xNilai
        Y = yNilai
    End Sub ' New

    ' properti X
    Public Property X() As Integer

        Get
            Return mX
        End Get

        Set(ByVal xNilai As Integer)
            mX = xNilai ' tidak perlu validasi
        End Set

    End Property ' X

    ' properti Y
    Public Property Y() As Integer

        Get
            Return mY
        End Get

        Set(ByVal yNilai As Integer)
            mY = yNilai ' tidak perlu validasi
        End Set

    End Property ' Y

    ' menghasilkan representasi String atas CTitik
    Public Overrides Function ToString() As String
        Return "[" & mX & ", " & mY & "]"
    End Function ' ToString

End Class ' CTitik

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
' Kode 9.2: Lingkaran.vb
' Kelas CLingkaran mewarisi kelas CTitik.

Public Class CLingkaran
    Inherits CTitik ' CLingkaran mewarisi kelas CTitik

    Private mRadius As Double ' radius CLingkaran

    ' konstruktor default
    Public Sub New()

        ' pemanggilan implisit terhadap konstruktor CTitik terjadi di sini
        Radius = 0
    End Sub ' New

    ' konstruktor
    Public Sub New(ByVal xNilai As Integer, _
        ByVal yNilai As Integer, ByVal nilaiRadius As Double)

        ' menggunakan referensi MyBase ke konstruktor CTitik secara eksplisit
        MyBase.New(xNilai, yNilai)
        Radius = nilaiRadius
    End Sub ' New

    ' properti Radius
    Public Property Radius() As Double

        Get
            Return mRadius
        End Get

        Set(ByVal nilaiRadius As Double)

            If nilaiRadius > 0 Then
                mRadius = nilaiRadius
            End If

        End Set

    End Property ' Radius

    ' menghitung diameter CLingkaran
    Public Function Diameter() As Double
        Return mRadius * 2
    End Function ' Diameter

    ' menghitung keliling CLingkaran
    Public Function Keliling() As Double
        Return Math.PI * Diameter()
    End Function ' Keliling

    ' menghitung luas CLingkaran
    Public Overridable Function Luas() As Double
        Return Math.PI * mRadius ^ 2
    End Function ' Luas

    ' menghasilkan representasi String atas CLingkaran
    Public Overrides Function ToString() As String

        ' menggunakan referensi MyBase untuk menghasilkan representasi String CLingkaran
        Return "Pusat= " & MyBase.ToString() & _
        "; Radius = " & mRadius
    End Function ' ToString

End Class ' CLingkaran

Kelas CUji (kode 9.3) mendemonstrasikan penugasan referensi kelas terderivasi kepada referensi kelas basis dan melakukan casting terhadap referensi kelas basis menjadi referensi kelas terderivasi. Baris 11-12 mendeklarasikan dua referensi CTitik (titik1 dan titik2) dan dua referensi CLingkaran (lingkaran1 dan lingkaran2). Baris 14-15 menugaskan sebuah objek CTitik kepada titik1 dan menugaskan sebuah objek CLingkaran kepada lingkaran1. Baris 17-18 memanggil metode ToString pada tiap objek, kemudian menampilkan String keluaran agar menunjukkan nilai-nilai yang digunakan dalam menginisialisasi setiap objek. Karena titik1 adalah sebuah objek CTitik, metode ToString dari titik1 menampilkan objek sebagai sebuah CTitik. Sama halnya, karena lingkaran1 adalah sebuah objek CLingkaran, metode ToSting dari lingkaran1 menampilkan objek sebagai sebuah CLingkaran.

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
' Kode 9.3: Uji.vb
' Demonstrasi pewarisan dan polimorfisme.

Imports System.Windows.Forms

Class CUji

    ' demonstrasi relasi "adalah suatu"
    Shared Sub Main()
        Dim keluaran As String
        Dim titik1, titik2 As CTitik
        Dim lingkaran1, lingkaran2 As CLingkaran

        titik1 = New CTitik(30, 50)
        lingkaran1 = New CLingkaran(120, 89, 2.7)

        keluaran = "CTitik titik1: " & titik1.ToString() & _
        vbCrLf & "CLingkaran lingkaran1: " & lingkaran1.ToString()

        ' menggunakan relasi adalah-suatu untuk menugaskan CLingkaran kepada referensi CTitik
        titik2 = lingkaran1

        keluaran &= vbCrLf & vbCrLf & _
        "CLingkaran lingkaran1 (via titik2): " & titik2.ToString()

        ' downcast (cast referensi kelas basis menjadi tipe data
        ' kelas terderivasi) titik2 menjadi lingkaran2
        lingkaran2 = CType(titik2, CLingkaran) ' hanya diijinkan via cast

        keluaran &= vbCrLf & vbCrLf & _
        "CLingkaran lingkaran1 (via lingkaran2): " & lingkaran2.ToString()

        keluaran &= vbCrLf & "Luas lingkaran1 (via lingkaran2): " & _
        String.Format("{0:F}", lingkaran2.Luas())

        ' menugaskan objek CTitik kepada referensi CLingkaran
        If (TypeOf titik1 Is CLingkaran) Then
            lingkaran2 = CType(titik1, CLingkaran)
            keluaran &= vbCrLf & vbCrLf & "cast berhasil"
        Else
            keluaran &= vbCrLf & vbCrLf & _
            "titik1 tidak menunjuk ke sebuah CLingkaran"
        End If

        MessageBox.Show(keluaran, _
        "Demonstrasi relasi 'adalah suatu' ")
    End Sub ' Main

End Class ' CUji



Gambar 9.1 Keluaran program pada kode 9.3


Baris 21 menugaskan lingkaran1 (sebuah referensi ke objek kelas terderivasi) kepada titik2 (sebuah referensi kelas basis). Dalam Visual Basic, adalah hal yang dapat diterima untuk menugaskan sebuah referensi kelas terderivasi kepada sebuah referensi kelas basis, karena pewarisan memiliki relasi “adalah suatu”.  Sebuah CLingkaran adalah suatu CTitik, karena kelas CLingkaran mewarisi kelas CTitik. Namun, penugasan sebuah referensi kelas basis kepada referensi kelas terderivasi adalah tindakan berbahaya, seperti yang akan didiskusikan nanti.

Baris 23-24 memanggil titik2.ToString dan menampilkan hasilnya pada keluaran. Ketika Visual Basic menjumpai Overridable pada suatu pemanggilan metode (seperti metode ToString), Visual Basic akan menentukan versi metode sesuai yang akan dipanggil berdasarkan tipe objek, bukan berdasarkan tipe referensi yang menunjuk objek. Pada kasus ini, referensi titik2 menunjuk ke sebuah objek CLingkaran, jadi Visual Basic akan memanggil metode ToString objek CLingkaran (baris 24), bukan memanggil metode ToString objek CTitik. Keputusan atas metode mana yang akan dipanggil merupakan salah satu contoh polimorfisme, sebuah konsep yang akan didiskusikan secara detil pada bab ini. Perhatikan bahwa, jika titik2 mereferensi objek CTitik, bukan objek CLingkaran, maka Visual Basic akan memanggil metode ToSting objek CTitik.

Pada beberapa bab terdahulu, telah digunakan metode Convert.ToInt32 dan Convert.ToDouble untuk mengkonversi berbagai tipe built-in Visual Basic. Sekarang, dilakukan konversi antar referensi objek dengan tipe didefinisikan-pengguna. Di sini digunakan metode CType untuk melakukan konversi ini, yang dikenal dengan cast. Jika cast yang dilakukan valid, program akan memperlakukan referensi kelas basis sebagai referensi kelas terderivasi. Jika cast tak-valid, Visual Basic akan melemparkan sebuah InvalidCastException, yang mengindikasikan bahwa operasi cast tidak diijinkan. Eksepsi akan didiskusikan pada Bab 10.

Baris 28 mengcast titik2, yang sebelumnya menunjuk ke sebuah objek CLingkaran (lingkaran1), menjadi sebuah CLingkaran dan menugaskan hasilnya pada lingkaran2. Seperti didiskusikan sebelumnya, cast ini sangat berbahaya jika titik2 sebelumnya mereferensi sebuah CTitik. Baris 30-31 memanggil metode ToString dari objek CLingkaran, yang saat ini ditunjuk oleh lingkaran2 (perhatikan bahwa baris keempat pada keluaran mendemonstrasikan bahwa metode ToString dari objek CLingkaran lah yang dipanggil). Baris 33-34 menghitung Luas dari lingkaran2 dan memformatnya dengan metode String.Format. Format “{0:F}” (baris 34) menspesifikasi pemformatan.

Baris 38 menggunakan metode CType untuk mengcast titik1 menjadi sebuah CLingkaran. Ini merupakan operasi yang berbahaya, karena titik1 menunjuk ke sebuah objek CTitik dan objek CTitik bukanlah sebuah CLingkaran. Objek hanya dapat dicast menjadi tipenya sendiri atau menjadi tipe kelas basisnya. Jika statemen ini dieksekusi, Visual Basic akan menentukan bahwa titik1 mereferensi sebuah objek CTitik, mengenali operasi cast menjadi CLingkaran adalah hal yang berbahaya, dan mengeluarkan pesan InvalidCastException. Namun, eksekusi terhadap statemen ini dicegah dengan penggunaan struktur If/Else (baris 37-43). Kondisi pada baris 37 menggunakan operator TypeOf untuk menentukan apakah objek yang ditunjuk oleh titik1 “adalah suatu” CLingkaran atau tidak. Operator TypeOf menentukan tipe objek yang ditunjuk oleh operandnya. Tipe tersebut kemudian dibandingkan dengan CLingkaran. Pada contoh ini, titik1 tidak menunjuk ke sebuah CLingkaran, jadi kondisi akan bernilai False, dan baris 41-42 akan menampilkan keluaran sebagai sebuah String yang mengindikasikan hasil tersebut. Perhatikan bahwa perbandingan Is akan bernilai True jika kedua operand bertipe sama atau jika operand kiri adalah kelas yang diderivasi (mewarisi) dari kelas pada operand kanan.


Metode dan Kelas Abstrak
Ketika Anda berpikir tentang kelas sebagai sebuah tipe, Anda pasti mengasumsikan bahwa program akan menciptakan objek-objek dengan tipe kelas itu. Namun, ada beberapa kasus dimana sangat berguna untuk mendefinisikan kelas, sehingga programer tidak berniat untuk menginstansiasi sembarang objek dari kelas tersebut. Kelas semacam itu dinamakan kelas abstrak. Karena kelas seperti itu biasanya dipakai sebagai kelas basis di dalam pewarisan, biasanya kelas semacam itu dinamakan dengan kelas basis abstrak. Kelas tersebut tidak dapat dipakai untuk menginstansiasi objek. Kelas abstrak adalah kelas yang tak utuh. Kelas terderivasi harus mendefinisikan “potongan-potongan” yang hilang dari kelas basis abstrak. Kelas abstrak biasanya memuat satu atau lebih metode abstrak atau properti abstrak, yaitu metode dan properti yang tidak menyediakan implementasi. Kelas terderivasi harus mendefinisikan-ulang metode dan properti abstrak yang diwarisi agar memampukan objek kelas terderivasi diinstansiasi.

Kegunaan dari kelas abstrak adalah menyediakan kelas basis yang cocok dan sesuai bagi kelas-kelas terderivasi. Kelas, yang dapat menginstansiasi objek, dinamakan dengan kelas konkrit. Kelas semacam itu menyediakan implementasi atas setiap metode dan properti yang didefinisikan. Anda bisa memiliki sebuah kelas basis abstrak CObjekDuaDimensi dan menderivasi beberapa kelas konkrit, seperti CPersegi, CLingkaran, dan CSegitiga. Anda juga dapat memiliki sebuah kelas basis abstrak CObjekTigaDimensi dan menderivasi beberapa kelas konkrit, seperti CKubik, CBola, dan CSilinder.

Sebuah kelas dijadikan abstrak dengan mendeklarasikannya menggunakan katakunci MustInherit. Suatu hirarki tidak harus memuat kelas kelas MustInherit, tetapi sistem berorientasi objek yang baik selalu memiliki hirarki kelas dengan kelas basis MustInherit. Contoh yang baik untuk ini adalah hirarki bangun pada Gambar 8.3. Hirarki tersebut dimulai dengan kelas basis abstrak MustInherit CBangun. Pada level berikutnya di dalam hirarki, dimiliki dua kelas basis abstrak MustInherit, sebut saja CBangunDuaDimensi dan CBangunTigaDimensi. Pada level berikutnya di dalam hirarki, didefinisikan dua kelas konkrit untuk bangun dua dimensi, CPersegi dan CLingkaran, dan untuk bangun tiga dimensi, sebut saja CKubik dan CKerucut.

Kelas MustInhenrit harus menspesifikasi metode atau properti abstraknya. Visual Basic menyediakan katakunci MustOverride untuk mendeklarasikan metode atau properti abstrak. Metode dan properti MustOverride tidak menyediakan implementasi. Jika Anda menyediakannya, akan terjadi error sintaks. Setiap kelas terderivasi harus mendefinisikan-ulang semua metode dan properti MustOverride kelas basis (menggunakan katakunci Overrides) dan menyediakan implementasi konkrit atas metode dan properti tersebut. Sembarang kelas yang memuat metode MustOverride harus dideklarasikan MustInherit. Perbedaan antara metode MustOverride dengan metode Overridable adalah bahwa metode Overridable memiliki implementasi dan kelas terderivasi memiliki opsi dalam mendefinisikan-ulang atau tidak mendefinisikan-ulang metode tersebut; sebaliknya, metode MustOverride tidak menyediakan implementasi dan kelas terderivasi harus mendefinisikan-ulang metode tersebut.

Meskipun Anda tidak bisa menginstansiasi objek dari kelas basis MustInherit, Anda dapat memakai kelas basis MustInherit untuk mendeklarasikan referensi; referensi itu dapat menunjuk ke instans dari sembarang kelas konkrit yang diderivasi dari kelas MustInherit. Program dapat menggunakan referensi semacam itu untuk memanipulasi instans dari kelas terderivasi secara polimorfik.

Sekarang akan didiskusikan satu lagi aplikasi polimorfisme. Sebuah screen manager ingin menampilkan pelbagai objek, termasuk beberapa tipe objek baru yang ditambahkan programer ke dalam sistem. Sistem akan menampilkan berbagai bangun, seperti CLingkaran, CSegitiga atau CPersegipanjang, yang diderivasi dari kelas MustInherit, CBangun. Kemudian screen manager menggunakan referensi kelas basis bertipe CBangun untuk mengelola objek-objek yang akan ditampilkan. Untuk menggambar sembarang objek (tidak memandang pada level mana kelas objek berada di dalam hirarki pewarisan), screen manager menggunakan sebuah referensi kelas basis untuk memanggil metode Gambar pada objek terkait. Metode Gambar adalah sebuah metode MustOverride di dalam kelas basis CBangun; oleh karena itu, setiap kelas terderivasi harus mendefinisikan-ulang metode Gambar. Setiap objek CBangun di dalam hirarki pewarisan mengetahui bagaimana menggambar dirinya sendiri. Screen manager tidak perlu khawatir tentang tipa setiap objek.


Studi Kasus: Mewarisi dan Mengimplementasikan Antarmuka
Pada contoh berikutnya (kode 9.4 – 9.8) akan diuji-ulang hirarki CTitik, CLingkaran, dan CSilinder yang telah dieksplorasi pada Bab 8. Pada contoh ini, hirarki diawali dengan kelas basis MustInherit, CBangun (kode 9.4). Hirarki ini mendemonstrasikan kekuatan dari polimorfisme.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
' Kode 9.4: Bangun.vb
' Demonstrasi hirarki bangun menggunakan kelas MustInherit.

Imports System.Windows.Forms

Public MustInherit Class CBangun

    ' menghasilkan luas bangun
    Public Overridable Function Luas() As Double
        Return 0
    End Function ' Luas

    ' menghasilkan volume bangun
    Public Overridable Function Volume() As Double
        Return 0
    End Function ' Volume

    ' metode yang harus didefinisikan-ulang, yang menghasilkan nama bangun
    Public MustOverride ReadOnly Property Nama() As String

End Class ' CBangun

Kelas CBangun mendefinisikan dua metode konkrit dan satu properti abstrak. Karena semua bangun memiliki luas dan volume sendiri, maka dicantumkan metode Luas (baris 9-11) dan Volume (baris 14-16), yang menghasilkan luas dan volume bangun. Volume dari bangun dua dimensi selalu bernilai nol, sedangkan volume bangun tiga dimensi selalu bernilai tak-nol positif. Dalam kelas CBangun, metode Luas dan Volume menghasilkan nilai balik nol, secara default. Programer dapat mendefinisikan-ulang kedua definisi tersebut di dalam kelas terderivasi. Properti Nama (baris 19) dideklarasikan sebagai MustOverride, sehingga kelas terderivasi harus mendefinisikan-ulang properti ini agar menjadi kelas konkrit.

Kelas CTitik2 (kode 9.5) mewarisi kelas MustInherit, CBangun, dan mendefinisikan-ulang properti MustOverride, Nama, yang menjadikan CTitik2 sebagai kelas konkrit. Luas dan volume suatu titik bernilai nol, sehingga kelas CTitik2 tidak mendefinisikan-ulang metode Luas dan Volume. Baris 59-65 mengimplementasikan properti Nama. Jika Anda tidak menyediakan implementasi ini, maka kelas CTitik2 akan menjadi kelas abstrak yang memerlukan katakunci MustInherit pada baris pertama dalam definisi kelas.


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
' Kode 9.5: Titik2.vb
' kelas CTitik2 merepresentasikan pasangan koordinat x-y.

Public Class CTitik2
    Inherits CBangun ' CTitik2 mewarisi kelas MustInherit CBangun

    ' koordinat titik
    Private mX, mY As Integer

    ' konstruktor default
    Public Sub New()

        ' pemanggilan implisit terhadap konstruktor Object terjadi di sini
        X = 0
        Y = 0
    End Sub ' New

    ' konstruktor
    Public Sub New(ByVal xNilai As Integer, _
        ByVal yNilai As Integer)

        ' pemanggilan implisit terhadap konstruktor Object terjadi di sini
        X = xNilai
        Y = yNilai
    End Sub ' New

    ' properti X
    Public Property X() As Integer

        Get
            Return mX
        End Get

        Set(ByVal xNilai As Integer)
            mX = xNilai ' tidak perlu validasi
        End Set

    End Property ' X

    ' properti Y
    Public Property Y() As Integer

        Get
            Return mY
        End Get

        Set(ByVal yNilai As Integer)
            mY = yNilai ' tidak perlu validasi
        End Set

    End Property ' Y

    ' menghasilkan representasi String atas CTitik2
    Public Overrides Function ToString() As String
        Return "[" & mX & ", " & mY & "]"
    End Function ' ToString

    ' implementasi properti MustOverride dari kelas CBangun
    Public Overrides ReadOnly Property Nama() As String

        Get
            Return "CTitik2"
        End Get

    End Property ' Nama

End Class ' CTitik2

Kode 9.6 mendefinisikan kelas CLingkaran2, yang mewarisi kelas CTitik2. Kelas CLingkaran2 memuat variabel anggota mRadius dan menyediakan properti Radius (baris 26-40) untuk mengakses mRadius. Perhatikan bahwa properti Radius tidak dideklarasikan sebagai Overridable, sehingga kelas yang diderivasi dari kelas ini tidak dapat mendefinisikan-ulang properti ini. Sebuah lingkaran memiliki volume nol, jadi Anda tidak perlu mendefinisikan-ulang metode kelas basis Volume. CLingkaran2 bisa saja mewarisi metode ini dari kelas CTitik2, yang mewarisi metode tersebut dari CBangun. Tetapi, lingkaran memiliki luas, sedangkan CTitik2 tidak memiliki luas, sehingga CLingkaran2 mendefinisikan-ulang metode Luas dari kelas CBangun (baris 53-55). Properti Nama (baris 66-72) dari kelas CLingkaran2 mendefinisikan-ulang properti Nama dari kelas CTitik2.

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
' Kode 9.6: Lingkaran2.vb
' Kelas CLingkaran2 mewarisi kelas CTitik.

Public Class CLingkaran2
    Inherits CTitik2 ' CLingkaran2 mewarisi kelas CTitik2

    Private mRadius As Double ' radius CLingkaran

    ' konstruktor default
    Public Sub New()

        ' pemanggilan implisit terhadap konstruktor CTitik terjadi di sini
        Radius = 0
    End Sub ' New

    ' konstruktor
    Public Sub New(ByVal xNilai As Integer, _
        ByVal yNilai As Integer, ByVal nilaiRadius As Double)

        ' menggunakan referensi MyBase ke konstruktor CTitik secara eksplisit
        MyBase.New(xNilai, yNilai)
        Radius = nilaiRadius
    End Sub ' New

    ' properti Radius
    Public Property Radius() As Double

        Get
            Return mRadius
        End Get

        Set(ByVal nilaiRadius As Double)

            If nilaiRadius > 0 Then
                mRadius = nilaiRadius
            End If

        End Set

    End Property ' Radius

    ' menghitung diameter CLingkaran2
    Public Function Diameter() As Double
        Return mRadius * 2
    End Function ' Diameter

    ' menghitung keliling CLingkaran2
    Public Function Keliling() As Double
        Return Math.PI * Diameter()
    End Function ' Keliling

    ' menghitung luas CLingkaran2
    Public Overrides Function Luas() As Double
        Return Math.PI * mRadius ^ 2
    End Function ' Luas

    ' menghasilkan representasi String atas CLingkaran2
    Public Overrides Function ToString() As String

        ' menggunakan referensi MyBase untuk menghasilkan representasi String CLingkaran2
        Return "Pusat= " & MyBase.ToString() & _
        "; Radius = " & mRadius
    End Function ' ToString

    ' mendefinisikan-ulang properti Nama dari kelas CTitik2
    Public Overrides ReadOnly Property Nama() As String

        Get
            Return "CLingkaran2"
        End Get

    End Property ' Nama

End Class ' CLingkaran2

Kode 9.7 mendefinisikan kelas CSilinder2 yang mewarisi kelas CLingkaran2. Kelas CSilinder2 memuat variabel anggota mTinggi dan properti Tinggi (baris 27-42) untuk mengakses mTinggi. Perhatikan bahwa properti Tinggi tidak dideklarasikan sebagai Overridable, jadi semua kelas yang diderivasi dari kelas CSilinder tidak dapat mendefinisikan-ulang properti ini. Sebuah silinder memiliki perhitungan luas dan volume yang berbedar dari lingkaran, jadi kelas ini mendefinisikan-ulang metode Luas (baris 45-47) untuk menghitung luas permukaan silinder  dan mendefinisikan metode Volume (baris 50-52). Properti Nama (baris 60-62) mendefinisikan-ulang properti Nama dari kelas CLingkaran2. Jika kelas ini tidak mendefinisikan-ulang properti Nama, maka kelas ini akan mewarisi properti Nama dari kelas CLingkaran2, yang secara salah akan menampilkan “CLingkaran2”.

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
' Kode 9.7: Silinder2.vb
' Kelas CSilinder2 mewarisi kelas CLingkaran2.

Public Class CSilinder2
    Inherits CLingkaran2  ' CSilinder2 mewarisi kelas CLingkaran2

    Protected mTinggi As Double

    ' konstruktor default
    Public Sub New()

        ' pemanggilan implisit terhadap konstruktor CLingkaran2 terjadi di sini
        Tinggi = 0
    End Sub ' New

    ' konstruktor empat-argumen
    Public Sub New(ByVal xNilai As Integer, _
        ByVal yNilai As Integer, ByVal nilaiRadius As Double, _
        ByVal nilaiTinggi As Double)

        ' pemanggilan eksplisit terhadap konstruktor CLingkaran2
        MyBase.New(xNilai, yNilai, nilaiRadius)
        Tinggi = nilaiTinggi ' menetapkan tinggi CSilinder2
    End Sub ' New

    ' properti Tinggi
    Public Property Tinggi() As Double

        Get
            Return mTinggi
        End Get

        ' menetapkan tinggi CSilinder jika nilai argumen positif
        Set(ByVal nilaiTinggi As Double)

            If nilaiTinggi >= 0 Then
                mTinggi = nilaiTinggi
            End If

        End Set

    End Property ' Tinggi

    ' mendefinisikan-ulang Luas untuk menghitung luas CSilinder2
    Public Overrides Function Luas() As Double
        Return 2 * MyBase.Luas + MyBase.Keliling * mTinggi
    End Function ' Luas

    ' menghitung volume CSilinder2
    Public Overrides Function Volume() As Double
        Return MyBase.Luas * mTinggi
    End Function ' Volume

    ' mengkonversi CSilinder2 menjadi String
    Public Overrides Function ToString() As String
        Return MyBase.ToString() & "; Tinggi = " & mTinggi
    End Function ' ToString

    ' mendefinisikan-ulang properti Nama dari kelas CLingkaran2
    Public Overrides ReadOnly Property Nama() As String

        Get
            Return "CSilinder2"
        End Get

    End Property ' Nama

End Class ' CSilinder2

Kode 9.8 mendefinisikan kelas CUji2, memiliki metode Main untuk menciptakan sebuah objek dari tiap kelas konkrit dan memanipulasi objek-objek tersebut secara polimorfik menggunakan array yang memuat beberapa referensi CBangun. Baris 11-13 menginstansiasi objek CTitik2 (titik), objek CLingkaran2 (lingkaran), dan objek CSilinder2 (silinder). Selanjutnya, baris 16 menginstansiasi array arrayBangun, yang memua tiga referensi CBangun. Baris 19 menugaskan referensi titik untuk menunjuk ke elemen array arrayBangun(0), baris 22 menugaskan referensi lingkaran untuk menunjuk ke elemen array arrayBangun(1), dan baris 25 menugaskan referensi silinder untuk menunjuk ke elemen array arrayBangun(2). Ketiga penugasan ini mungkin dilakukan, karena sebuah CTitik2 adalah sebuah CBangun, sebuah CLingkaran2 adalah sebuah CBangun, dan sebuah CSilinder2 adalah sebuah CBangun. Oleh karena itu, Anda dapat menugaskan instans dari kelas-kelas terderivasi, CTitik2, CLingkaran2, dan CSilinder2 kepada referensi kelas basis CBangun.

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
' Kode 9.8: Uji2.vb
' Demonstrasi polimorfisme di dalam hirarki Titik-Lingkaran-Silinder.

Imports System.Windows.Forms

Class CUji2

    Shared Sub Main()

        ' instansiasi objek CTitik2, c, dan CSilinder2
        Dim titik As New CTitik2(7, 11)
        Dim lingkaran As New CLingkaran2(22, 8, 3.5)
        Dim silinder As New CSilinder2(10, 10, 3.3, 10)

        ' instansiasi array yang memuat tiga referensi kelas basis
        Dim arrayBangun(2) As CBangun

        ' arrayBangun(0) menunjuk ke objek CTitik2
        arrayBangun(0) = titik

        ' arrayBangun(1) menunjuk ke objek CLingkaran2
        arrayBangun(1) = lingkaran

        ' arrayBangun(2) menunjuk ke objek CSilinder2
        arrayBangun(2) = silinder

        Dim keluaran As String = titik.Nama & ": " & _
        titik.ToString() & vbCrLf & lingkaran.Nama & ": " & _
        lingkaran.ToString() & vbCrLf & silinder.Nama & _
        ": " & silinder.ToString()

        Dim bangun As CBangun

        ' menampilkan nama, luas, dan volume untuk setiap objek di dalam
        ' arrayBangun secara polimorfik
        For Each bangun In arrayBangun
            keluaran &= vbCrLf & vbCrLf & bangun.Nama & ": " & _
            bangun.ToString() & vbCrLf & "Luas = " & _
            String.Format("{0:F}", bangun.Luas) & vbCrLf & _
            "Volume = " & String.Format("{0:F}", bangun.Volume)
        Next

        MessageBox.Show(keluaran, "Demonstrasi Polimorfisme")
    End Sub ' Main

End Class ' CUji2



Gambar 9.2 Keluaran program pada kode 9.8

Baris 27-30 memanggil properti Nama dan metode ToString untuk objek titik, lingkaran, dan silinder. Properti Nama menghasilkan nama kelas objek dan metode ToString menghasilkan representasi String atas objek (sepasang koordinat x-y, radius, dan tinggi, tergantung pada tiap tipe objek). Perhatikan bahwa baris 27-30 menggunakan referensi kelas terderivasi untuk memanggil metode dan properti dari setiap objek kelas terderivasi.

Sebaliknya, struktur For Each (baris 36-41) menggunakan referensi kelas basis CBangun untuk memanggil metode dan properti setiap objek kelas terderivasi. Struktur For Each memanggil properti Nama dan metode ToString, Luas dan Volume untuk tiap referensi CBangun di dalam arrayBangun. Properti dan metode dipanggil pada tiap objek di dalam arrayBangun.


Kelas NotInheritable dan Metode NotOverridable
Sebuah kelas yang dideklarasikan NotInheritable tidak dapat dijadikan kelas basis. Programer menggunakan fitur ini untuk mencegah pewarisan melebihi kelas NotInheritable di dalam hirarki. Kelas NotInheritable berlawanan dengan kelas MustInherit. Kelas NotInheritable adalah sebuah kelas konkrit yang tidak dapat berperan sebagai kelas basis, sedangkan kelas MustInherit adalah sebuah kelas basis yang dapat berperan sebagai kelas basis.

Sebuah metode yang dideklarasikan Overridable di dalam kelas basis dapat dideklarasikan NotOverridable di dalam kelas terderivasi. Ini akan mencegah pendefinisian-ulang metode tersebut di dalam semua kelas yang diderivasi dari kelas terderivasi tersebut. Semua kelas yang diderivasi dari kelas yang memuat metode NotOverridable harus menggunakan implementasi metode pada kelas tersebut. Metode yang dideklarasikan Shared dan metode yang dideklarasikan Private secara implisit adalah NotOverridable.


Studi Kasus: Sistem Penggajian Menggunakan Polimorfisme
Akan digunakan kelas abstrak (dideklarasikan sebagai MustInherit), metode abstrak (dideklarasikan sebagai MustOverride) dan polimorfisme untuk melakukan berbagai perhitungan penggajian yang berbeda untuk pelbagai tipe karyawan. Akan dimulai dengan menciptakan sebuah kelas basis CKaryawan. Empat kelas yang diderivasi dari CKaryawan adalah CBoss (digaji tetap secara mingguan, tanpa memandang jumlah jam kerja), CKaryawanKomisi (dengan gaji pokok tetap ditambah dengan persentasi penjualan), CKaryawanItem (digaji tiap item yang dihasilkan), dan CKaryawanPerjam (digaji berdasarkan jumlah jam kerja dengan “satu setengah kali” gaji untuk lembur). Pada contoh ini, semua kelas yang mewarisi CKaryawan dideklarasikan sebagai NotInheritable, karena tidak dimaksudkan untuk menderivasi kelas dari kelas-kelas tersebut.

Aplikasi harus menentukan penghasilan mingguan untuk semua tipe karyawan, sehingga setiap kelas yang diderivasi dari CKaryawan memerlukan metode Penghasilan. Namun, setiap kelas terderivasi menggunakan perhitungan yang berbeda dalam menentukan penghasilan untuk tipe karyawan tertentu. Oleh karena itu, metode Penghasilan dideklarasikan sebagai MustOverride di dalam kelas CKaryawan dan kelas CKaryawan dideklarasikan sebagai kelas MustInherit. Setiap kelas terderivasi akan mendefinisikan-ulang metode Penghasilan agar dapat menghitung penghasilan tiap tipe karyawan.

Untuk menghitung penghasilan karyawan, program dapat menggunakan sebuah referensi kelas basis yang menunjuk ke objek kelas terderivasi dan memanggil metode Penghasilan. Dalam sistem penggajian, pelbagai objek CKaryawan dapat direferensi oleh elemen-elemen individual di dalam sebuah array yang memuat beberapa referensi CKaryawan. Program kemudian akan menjelajah array, elemen demi elemen, menggunakan referensi CKaryawan untuk memanggil metode Penghasilan yang sesuai untuk setiap objek.

Anda bisa melihat kelas CKaryawan (kode 9.9). Anggora-anggota Public mencakup sebuah konstruktor (baris 10-15) yang mengambil sebagai argumen nama pertama dan nama akhir seorang karyawan; properti NamaPertama (baris 18-28) dan NamaAkhir (baris 31-41); metode ToString (baris 44-46) yang menghasilkan nilai balik berupa nama pertama dan nama akhir yang dipisahkan dengan spasi; dan metode MustOverride, Penghasilan (baris 50). Katakunci MustInherit (baris 4) mengindikasikan bahwa kelas CKaryawan adalah kelas abstrak; jadi, ia tidak dapat dipakai untuk menginstansiasi objek CKaryawan. Metode Penghasilan dideklarasikan sebagai MustOverride, sehingga kelas CKaryawan tidak menyediakan implementasi metode tersebut. Semua kelas yang diderivasi secara langsung dari kelas CKaryawan, kecuali kelas terderivasi abstrak, harus mendefinisikan metode ini. Metode Penghasilan adalah abstrak di dalam kelas CKaryawan, karena Anda tidak dapat menghitung penghasilan secara umum untuk semua tipe karyawan.

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
' Kode 9.9: Karyawan.vb
' Kelas basis abstrak untuk semua kelas terderivasi.

Public MustInherit Class CKaryawan

    Private mNamaPertama As String
    Private mNamaAkhir As String

    ' konstruktor
    Public Sub New(ByVal nilaiNamaPertama As String, _
    ByVal nilaiNamaAkhir As String)

        NamaPertama = nilaiNamaPertama
        NamaAkhir = nilaiNamaAkhir
    End Sub ' New

    ' properti NamaPertama
    Public Property NamaPertama() As String

        Get
            Return mNamaPertama
        End Get

        Set(ByVal nilaiNamaPertama As String)
            mNamaPertama = nilaiNamaPertama
        End Set

    End Property ' NamaPertama

    ' properti NamaAkhir
    Public Property NamaAkhir() As String

        Get
            Return mNamaAkhir
        End Get

        Set(ByVal nilaiNamaAkhir As String)
            mNamaAkhir = nilaiNamaAkhir
        End Set

    End Property ' NamaAkhir

    ' mendapatkan representasi String atas karyawan
    Public Overrides Function ToString() As String
        Return mNamaPertama & " " & mNamaAkhir
    End Function ' ToString

    ' metode abstrak harus diimplementasikan untuk setiap kelas terderivasi
    ' dari CKaryawan dalam menghitung penghasilan spesifik
    Public MustOverride Function Penghasilan() As Decimal

End Class ' CKaryawan

Kelas CBoss (kode 9.10) mewarisi CKaryawan. Konstruktor kelas CBoss (baris 10-15) menerima sebagai argumen nama pertama, nama akhir, dan gaji. Konstruktor melewatkan nama pertama dan nama akhir kepada konstruktor CKaryawan (baris 13), yang menginisialisasi anggota mNamaPertama dan mNamaAkhir, yang merupakan bagian kelas basis di dalam objek kelas terderivasi. Metode-metode lain yang dimuat di dalam CBoss mencakup metode Penghasilan (baris 36-38), yang mendefinisikan perhitungan dari penghasilan seorang boss, dan metode ToString (baris 41-43), yang menghasilkan nilai balik berupa sebuah String yang mengindikasikan tipe karyawan (yaitu, “CBoss: “) dan nama boss. Kelas CBoss juga menyertakan properti GajiMingguan (baris 18-33), yang menetapkan dan memperoleh nilai variabel anggota mGaji. Perhatikan bahwa properti ini hanya memastikan bahwa mGaji tidak dapat memuat nilai negatif.

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
' Kode 9.10: Boss.vb
' Kelas CBoss mewarisi CKaryawan.

Public NotInheritable Class CBoss
    Inherits CKaryawan

    Private mGaji As Decimal

    ' konstruktor untuk CBoss
    Public Sub New(ByVal nilaiNamaPertama As String, _
    ByVal nilaiNamaAkhir As String, ByVal nilaiGaji As Decimal)

        MyBase.New(nilaiNamaPertama, nilaiNamaAkhir)
        GajiMingguan = nilaiGaji
    End Sub ' New

    ' properti GajiMingguan
    Public Property GajiMingguan() As Decimal

        Get
            Return mGaji
        End Get

        Set(ByVal nilaiGajiBoss As Decimal)

            ' validasi mGaji
            If nilaiGajiBoss > 0 Then
                mGaji = nilaiGajiBoss
            End If

        End Set

    End Property ' GajiMingguan

    ' mendefinisikan-ulang metode kelas basis untuk menghitung penghasilan Boss
    Public Overrides Function Penghasilan() As Decimal
        Return GajiMingguan
    End Function ' Penghasilan

    ' menghasilkan nama Boss
    Public Overrides Function ToString() As String
        Return "CBoss: " & MyBase.ToString()
    End Function ' ToString

End Class ' CBoss

Kelas CKaryawanKomisi (kode 9.11) juga mewarisi kelas CKaryawan. Konstruktor untuk kelas ini (baris 12-21) menerima sebagai argumen nama pertama, nama akhir, gaji, komisi, dan kuantitas item yang terjual. Baris 17 melewatkan nama pertama dan nama akhir kepada konstruktor CKaryawan. Kelas KaryawanKomisi juga menyediakan properti Gaji (baris 24-39), Komisi (baris 42-57), dan Kuantitas (baris 60-75); metode Penghasilan (baris 78-80), yang menghitung gaji karyawan; dan metode ToString (baris 83-85), yang menghasilkan nilai balik berupa sebuah String yang mengindikasikan tipe karyawan (yaitu, “CKaryawanKomisi: “) dan nama karyawan.
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
' Kode 9.11: KaryawanKomisi.vb
' Implementasi CKaryawan untuk karyawan komisi.

Public NotInheritable Class CKaryawanKomisi
    Inherits CKaryawan

    Private mGaji As Decimal ' gaji pokok per minggu
    Private mKomisi As Decimal ' komisi per item yang terjual
    Private mKuantitas As Integer ' total item terjual

    ' konstruktor untuk kelas CKaryawanKomisi
    Public Sub New(ByVal nilaiNamaPertama As String, _
    ByVal nilaiNamaAkhir As String, ByVal nilaiGaji As Decimal, _
    ByVal nilaiKomisi As Decimal, _
    ByVal nilaiKuantitas As Integer)

        MyBase.New(nilaiNamaPertama, nilaiNamaAkhir)
        Gaji = nilaiGaji
        Komisi = nilaiKomisi
        Kuantitas = nilaiKuantitas
    End Sub ' New

    ' properti Gaji
    Public Property Gaji() As Decimal

        Get
            Return mGaji
        End Get

        Set(ByVal nilaiGaji As Decimal)

            ' validasi mGaji
            If nilaiGaji > 0 Then
                mGaji = nilaiGaji
            End If

        End Set

    End Property ' Gaji

    ' properti Komisi
    Public Property Komisi() As Decimal

        Get
            Return mKomisi
        End Get

        Set(ByVal nilaiKomisi As Decimal)

            ' validasi mKomisi
            If nilaiKomisi > 0 Then
                mKomisi = nilaiKomisi
            End If

        End Set

    End Property ' Komisi

    ' properti Kuantitas
    Public Property Kuantitas() As Integer

        Get
            Return mKuantitas
        End Get

        Set(ByVal nilaiKuantitas As Integer)

            ' validasi mKuantitas
            If nilaiKuantitas > 0 Then
                mKuantitas = nilaiKuantitas
            End If

        End Set

    End Property ' Kuantitas

    ' mendefinisikan-ulang metode untuk menghitung penghasilan KaryawanKomisi
    Public Overrides Function Penghasilan() As Decimal
        Return Gaji + Komisi * Kuantitas
    End Function ' Penghasilan

    ' menghasilkan nama karyawan komisi
    Public Overrides Function ToString() As String
        Return "CKaryawanKomisi: " & MyBase.ToString()
    End Function ' ToString

End Class ' CKaryawanKomisi

Kelas CKaryawanItem (kode 9.12) mewarisi kelas CKaryawan. Konstruktor kelas ini (baris 11-19) menerima sebagai argumen nama pertama, nama akhir, gaji per item, dan kuantitas item yang dihasilkan. Baris 16 kemudian melewatkan nama pertama dan nama akhir kepada konstruktor kelas basis CKaryawan. Kelas CKaryawanItem juga menyediakan properti GajiPerItem (baris 22-37) dan Kuantitas (baris 40-55); metode Penghasilan (baris 58-60), yang menghitung penghasilan karyawan per item; dan metode ToString (baris 63-65), yang menghasilkan nilai balik berupa sebuah String yang mengindikasikan tipe karyawan (yaitu, “CKaryawanItem: “) dan nama karyawan item.

Kelas CKaryawanPerJam (kode 9.13) mewarisi kelas CKaryawan. Konstruktor untuk kelas ini (baris 11-18) menerima sebagai argumen nama pertama, nama akhir, gaji, dan jumlah jam kerja. Baris 15 melewatkan nama pertama dan nama akhir kepada konstruktor kelas basis CKaryawan. Kelas CKaryawanPerJam juga menyediakan properti GajiPerJam (baris 21-36) dan Jam (baris 39-54); metode Penghasilan (baris 57-67), yang menghitung penghasilan karyawan per jam; dan metode ToString (baris 70-72) yang menghasilkan nilai balik berupa sebuah String yang mengindikasikan tipe karyawan (yaitu, “CKaryawanPerJam: “) dan nama karyawan per jam.

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
' Kode 9.12: KaryawanItem.vb
' Kelas KaryawanItem diderivasi dari CKaryawan.

Public NotInheritable Class CKaryawanItem
    Inherits CKaryawan

    Private mJumlahPerItem As Decimal ' gaji per item
    Private mKuantitas As Integer ' kuantitas per minggu

    ' konstruktor untuk CKaryawanItem
    Public Sub New(ByVal nilaiNamaPertama As String, _
    ByVal nilaiNamaAkhir As String, _
    ByVal nilaiGajiPerItem As Decimal, _
    ByVal nilaiKuantitas As Integer)

        MyBase.New(nilaiNamaPertama, nilaiNamaAkhir)
        GajiPerItem = nilaiGajiPerItem
        Kuantitas = nilaiKuantitas
    End Sub ' New

    ' properti GajiPerItem
    Public Property GajiPerItem() As Decimal

        Get
            Return mJumlahPerItem
        End Get

        Set(ByVal nilaiGajiPerItem As Decimal)

            ' validasi mJumlahPerItem
            If nilaiGajiPerItem > 0 Then
                mJumlahPerItem = nilaiGajiPerItem
            End If

        End Set

    End Property ' GajiPerItem

    ' properti Kuantitas
    Public Property Kuantitas() As Integer

        Get
            Return mKuantitas
        End Get

        Set(ByVal nilaiKuantitas As Integer)

            ' validasi mKuantitas
            If nilaiKuantitas > 0 Then
                mKuantitas = nilaiKuantitas
            End If

        End Set

    End Property ' Kuantitas

    ' mendefinisikan-ulang metode kelas basis untuk menghitung penghasilan KaryawanItem
    Public Overrides Function Penghasilan() As Decimal
        Return Kuantitas * GajiPerItem
    End Function ' Penghasilan

    ' menghasilkan nama karyawan item
    Public Overrides Function ToString() As String
        Return "CKaryawanItem: " & MyBase.ToString()
    End Function ' ToString

End Class ' CKaryawanItem


Metode Main (baris 8-50) dari kelas CUji (kode 9.14) mendeklarasikan referensi CKaryawan, karyawan (baris 9). Setiap tipe karyawan ditangani dengan cara yang sama di dalam Main, sehingga yang didiskusikan hanya tentang manipulasi objek CBoss.

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
' Kode 9.13: KaryawanPerJam.vb
' Implementasi CKaryawan untuk karyawan per jam.

Public NotInheritable Class CKaryawanPerJam
    Inherits CKaryawan

    Private mGaji As Decimal ' gaji per jam
    Private mJamKerja As Double ' jam kerja selama seminggu

    ' konstruktor untuk kelas CKaryawanPerJam
    Public Sub New(ByVal nilaiNamaPertama As String, _
    ByVal nilaiNamaAkhir As String, _
    ByVal nilaiGaji As Decimal, ByVal nilaiJam As Double)

        MyBase.New(nilaiNamaPertama, nilaiNamaAkhir)
        GajiPerJam = nilaiGaji
        Jam = nilaiJam
    End Sub ' New

    ' properti GajiPerJam
    Public Property GajiPerJam() As Decimal

        Get
            Return mGaji
        End Get

        Set(ByVal nilaiGajiPerJam As Decimal)

            ' validasi mGaji
            If nilaiGajiPerJam > 0 Then
                mGaji = nilaiGajiPerJam
            End If

        End Set

    End Property ' GajiPerJam

    ' properti Jam
    Public Property Jam() As Double

        Get
            Return mJamKerja
        End Get

        Set(ByVal nilaiJam As Double)

            ' validasi mJamKerja
            If nilaiJam > 0 Then
                mJamKerja = nilaiJam
            End If

        End Set

    End Property ' Jam

    ' mendefinisikan-ulang metode kelas basis untuk menghitung penghasilan KaryawanPerJam
    Public Overrides Function Penghasilan() As Decimal

        ' menghitung untuk "satu dan setengah"
        If mJamKerja <= 40 Then
            Return Convert.ToDecimal(mGaji * mJamKerja)
        Else
            Return Convert.ToDecimal((mGaji * mJamKerja) + _
            (mJamKerja - 40) * 1.5 * mGaji)
        End If

    End Function ' Penghasilan

    ' menghasilkan nama karyawanperjam
    Public Overrides Function ToString() As String
        Return "CKaryawanPerJam: " & MyBase.ToString()
    End Function ' ToString

End Class ' CKaryawanPerJam

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
' Kode 9.14: Uji.vb
' Menampilkan penghasilan untuk tiap CKaryawan.

Imports System.Windows.Forms

Class CUji

    Shared Sub Main()
        Dim karyawan As CKaryawan ' referensi kelas basis
        Dim keluaran As String

        Dim boss As CBoss = New CBoss("DJumanggal", "Sianipar", 800)

        Dim karyawanKomisi As CKaryawanKomisi = _
            New CKaryawanKomisi("Undur", "Siahaan", 400, 3, 150)

        Dim karyawanItem As CKaryawanItem = _
            New CKaryawanItem("Robert", "Sianipar", _
            Convert.ToDecimal(2.5), 200)

        Dim karyawanPerJam As CKaryawanPerJam = _
            New CKaryawanPerJam("Rico", "Sianipar", _
            Convert.ToDecimal(13.75), 40)

        ' memakai referensi yang menunjuk ke sebuah CBoss
        karyawan = boss
        keluaran &= GetString(karyawan) & boss.ToString() & _
        " bergaji sebesar " & boss.Penghasilan.ToString("C") & vbCrLf & vbCrLf

        ' menggunakan referensi yang menunjuk ke CKaryawanKomisi
        karyawan = karyawanKomisi
        keluaran &= GetString(karyawan) & _
        karyawanKomisi.ToString() & " bergaji sebesar " & _
        karyawanKomisi.Penghasilan.ToString("C") & vbCrLf & vbCrLf

        ' memakai referensi yang menunjuk ke sebuah CKaryawanItem
        karyawan = karyawanItem
        keluaran &= GetString(karyawan) & karyawanItem.ToString() & _
        " bergaji sebesar " & karyawanItem.Penghasilan.ToString("C") _
        & vbCrLf & vbCrLf

        ' memakai referensi yang menunjuk ke sebuah CKaryawanPerJam
        karyawan = karyawanPerJam
        keluaran &= GetString(karyawan) & _
        karyawanPerJam.ToString() & " bergaji sebesar " & _
        karyawanPerJam.Penghasilan.ToString("C") & vbCrLf & vbCrLf

        MessageBox.Show(keluaran, "Demonstrasi Polimorfisme", _
        MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub ' Main

    ' menghasilkan String yang memuat informasi karyawan
    Shared Function GetString(ByVal pekerja As CKaryawan) As String
        Return pekerja.ToString() & " bergaji sebesar " & _
        pekerja.Penghasilan.ToString("C") & vbCrLf
    End Function ' GetString

End Class ' CUji



Gambar 9.3 Keluaran program pada kode 9.14


Baris 12 menugaskan sebuah objek CBoss kepada referensi CBoss, boss, dan melewatkan kepada konstruktornya nama pertama boss (“Djumanggal”), nama akhir (“Sianipar”), dan gaji mingguan (800). Baris 26 menugaskan referensi kelas terderivasi, boss, kepada referensi kelas basis CKaryawan, karyawan, sehingga dapat didemonstrasikan kemampuan polimorfik atas penghasilan boss. Baris 27 melewatkan referensi karyawan sebagai argumen kepada metode Private GetString (baris 53-56), yang secara polimorfik memanggil metode ToString dan Penghasilan pada objek CKaryawan. Pada titik ini, Visual Basic menentukan bahwa objek yang dilewatkan kepada GetString adalah bertipe CBoss, sehingga baris 54-55 memanggil metode CBoss, ToString dan Penghasilan.

Metode Penghasilan menghasilkan sebuah objek Decimal. Kemudian, pada objek tersebut, metode ToString dipanggil. Pada kasus ini, string “C”, yang dilewatkan kepada versi teroverload dari metode ToString, merupakan kepanjangan dari Currency.

Ketika metode GetString kembali ke Main, baris 27-28 secara eksplisit memanggil metode ToString dan Penghasilan melalui referensi CBoss, boss, untuk menunjukkan bahwa pemanggilan metode tersebut tidak menggunakan pemrosesan polimorfik. Keluaran yang dihasilkan pada baris 27-28 identik dengan yang dihasilkan metode ToString dan Penghasilan melalui referensi kelas basis, karyawan.


Studi Kasus: Menciptakan dan Menggunakan Antarmuka
Sekarang akan disajikan dua lagi contoh polimorfisme melalui penggunaan antarmuka, yang menspesifikasi himpunan layanan Public (metode dan properti) yang harus diimplementasikan oleh kelas. Antarmuka digunakan ketika tidak ada implementasi default yang akan diwarisi (tidak ada variabel instans dan tidak ada implementasi metode default). Sedangkan kelas abstrak paling baik digunakan untuk menyediakan data dan layanan untuk objek-objek di dalam relasi hirarki pewarisan.

Definisi antarmuka dimulai dengan katakunci Interface dan memuat sejumlah metode dan properti Public. Untuk menggunakan antarmuka, sebuah kelas harus menspesifikasi bahwa ia mengimplementasikan (Implements) antarmuka dan harus menyediakan implementasi atas tiap metode dan properti yang dispesifikasi di dalam definisi antarmuka. Memiliki sebuah kelas yang mengimplementasikan antarmuka adalah seperti menandatangani kontrak dengan kompiler yang menyatakan bahwa “kelas ini akan mendefinisikan semua metode dan properti yang dispesifikasi oleh antarmuka”.

Pada contoh ini, akan digunakan antarmuka IUsia (kode 9.15) untuk menghasilkan informasi usia bagi kelas COrang (kode 9.16) dan CPohon (kode 9.17). Definisi antarmuka IUsia diawali pada baris 4 dengan Public Interface dan berakhir pada baris 10 dengan End Interface. Baris 7-8 menspesifikasi properti Usia dan Nama, dimana setiap kelas yang mengimplementasikan antarmuka IUsia harus menyediakan implementasi atas kedua properti tersebut. Antarmuka IUsia mendeklarasikan kedua properti itu sebagai ReadOnly.

1
2
3
4
5
6
7
8
9
10
' Kode 9.15: IUsia.vb
' Antarmuka IUsia mendeklarasikan properti untuk menetapkan dan mendapatkan usia.

Public Interface IUsia

    ' kelas yang mengimplementasikan IUsia harus mendefinisikan kedua properti ini
    ReadOnly Property Usia() As Integer
    ReadOnly Property Nama() As String

End Interface ' IUsia

Baris 5 pada kode 9.16 menggunakan katakunci Implements untuk mengindikasikan bahwa kelas COrang mengimplementasikan antarmuka IUsia. Pada contoh ini, kelas COrang hanya mengimplementasikan satu antarmuka. Sebuah kelas dapat mengimplementasikan sebanyak mungkin antarmuka. Untuk mengimplementasikan lebih dari satu antarmuka, definisi kelas harus menyediakan daftar antarmuka, yang dipisahkan oleh koma, setelah katakunci Implements. Kelas COrang memiliki variabel anggota mTahunLahir, mNamaPertama, dan mNamaAkhir (baris 7-9), yang diinisialisasi oleh konstruktor pada baris 12-29. Karena kelas COrang mengimplementasikan antarmuka IUsia, kelas COrang harus mengimplementasikan properti Usia dan Nama, yang didefinisikan pada baris 32-39 dan baris 42-49. Properti Usia membolehkan klien untuk mendapatkan usia seseorang dan properti Nama menghasilkan sebuah String yang memuat NamaPertama dan NamaAkhir. Perhatikan bahwa properti Usia menghitung usia seseorang dengan mengurangkan mTahunLahir dari tahun sekarang (via properti Tahun dari properti Date.Now, yang menghasilkan tanggal sekarang).

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
' Kode 9.16: Orang.vb
' Kelas COrang memiliki hari lahir.

Public Class COrang
    Implements IUsia

    Private mTahunLahir As Integer
    Private mNamaPertama As String
    Private mNamaAkhir As String

    ' konstruktor menerima nama pertama, nama akhir, dan tanggal lahir
    Public Sub New(ByVal nilaiNamaPertama As String, _
        ByVal nilaiNamaAkhir As String, _
        ByVal nilaiTahunLahir As Integer)

        ' pemanggilan implisit terhadap konstruktor Object
        mNamaPertama = nilaiNamaPertama
        mNamaAkhir = nilaiNamaAkhir

        ' validasi tahun
        If (nilaiTahunLahir > 0 AndAlso _
        nilaiTahunLahir <= Date.Now.Year) Then

            mTahunLahir = nilaiTahunLahir
        Else
            mTahunLahir = Date.Now.Year
        End If

    End Sub ' New

    ' implementasi atas properti Usia dari antarmuka IUsia
    ReadOnly Property Usia() As Integer _
        Implements IUsia.Usia

        Get
            Return Date.Now.Year - mTahunLahir
        End Get

    End Property ' Usia

    ' implementasi properti Nama dari antarmuka IUsia
    ReadOnly Property Nama() As String _
        Implements IUsia.Nama

        Get
            Return mNamaPertama & " " & mNamaAkhir
        End Get

    End Property ' Nama

End Class ' COrang

Kelas CPohon (kode 9.17) juga mengimplementasikan antarmuka IUsia. Kelas CPohon memiliki variabel anggota mLingkar (baris 7), yang merepresentasikan jumlah lingkar pada batang pohon, dimana variabel ini berkaitan secara langsung dengan usia pohon. Konstruktor CPohon (baris 10-14) menerima sebagai argumen sebuah Integer yang menspesifikasi kapan pohon ditanam. Kelas CPohon mencakup metode TambahLingkar (baris 17-19), yang memampukan pengguna dalam menginkremen jumlah lingkar pada pohon. Karena kelas CPohon mengimplementasikan antarmuka IUsia, kelas CPohon harus mengimplementasikan properti Usia dan Nama, yang didefinisikan pada baris 22-29 dan baris 32-39. Properti Usia menghasilkan nilai dari mLingkar, dan properti Nama menghasilkan StringPohon”.

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
' Kode 9.17: Pohon.vb
' Kelas CPohon memuat jumlah lingkar terkait dengan usia pohon.

Public Class CPohon
    Implements IUsia

    Private mLingkar As Integer

    ' konstruktor menerima tanggal penanaman pohon
    Public Sub New(ByVal tahunDitanam As Integer)

        ' pemanggilan implisit terhadap konstruktor Object
        mLingkar = Date.Now.Year - tahunDitanam
    End Sub ' New

    ' menginkremen mLingkar
    Public Sub TambahLingkar()
        mLingkar += 1
    End Sub ' TambahLingkar

    ' properti Usia
    ReadOnly Property Usia() As Integer _
        Implements IUsia.Usia

        Get
            Return mLingkar
        End Get

    End Property ' Usia

    ' implementasi properti Nama dari antarmuka IUsia
    ReadOnly Property Nama() As String _
     Implements IUsia.Nama

        Get
            Return "Pohon"
        End Get

    End Property ' Nama

End Class ' CPohon

Kelas CUji (kode 9.18) mendemonstrasikan polimorfisme pada beberapa objek dari kelas COrang dan CPohon. Baris 11 menginstansiasi objek pohon dari kelas CPohon, dan baris 12 menginstansiasi objek orang dari kelas COrang. Baris 15 mendeklarasikan iArrayUsia, sebuah array yang memuat dua referensi yang menunjuk ke objek IUsia. Baris 18 dan 21 menugaskan pohon dan orang kepada referensi pertama dan referensi kedua di dalam iArrayUsia. Baris 24-26 memanggil metode ToString pada pohon, kemudian memanggil propertinya, Usia dan Nama, untuk menghasilkan informasi usia dan nama untuk objek pohon. Baris 29-31 memanggil metode ToString pada orang, kemudian memanggil propertinya, Usia dan Nama, untuk menghasilkan informasi usia dan nama untuk objek orang. Selanjutnya, kedua objek tersebut akan dimanipulasi secara polimorfik melalui iArrayUsia, yang memuat referensi yang menunjuk ke objek IUsia. Baris 36-39 mendefinisikan sebuah struktur For-Each yang menggunakan properti Usia dan Nama untuk mendapatkan informasi usia dan nama bagi tiap objek IUsia di dalam iArrayUsia. Perhatikan bahwa Nama digunakan sehingga setiap objek di dalam iArrayUsia dapat “mengidentifikasi” dirinya di dalam keluaran program. Objek pohon dan orang dapat menggunakan metode ToString untuk melakukan ini, karena kelas CPohon dan COrang keduanya mewarisi kelas Object. Namun, ketika CUji berinteraksi dengan dua objek tersebut secara polimorfik, CUji hanya dapat menggunakan properti Usia dan Nama untuk setiap objek antarmuka. Karena antarmuka IUsia tidak menyediakan metode ToString, klien tidak dapat memanggil metode ToString melalui referensi antarmuka IUsia.

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
' Kode 9.18: Uji.vb
' Demonstrasi polimorfisme.

Imports System.Windows.Forms

Class CUji

    Shared Sub Main()

        ' instansiasi objek CPohon dan COrang
        Dim pohon As New CPohon(1977)
        Dim orang As New COrang("Djumanggal", "Sianipar", 1950)

        ' instansiasi array yang memuat referensi kelas basis
        Dim iArrayUsia(1) As IUsia

        ' iArrayUsia(0) mereferensi objek CPohon
        iArrayUsia(0) = pohon

        ' iArrayUsia(1) mereferensi objek COrang
        iArrayUsia(1) = orang

        ' menampilkan informasi pohon
        Dim keluaran As String = pohon.ToString() & ": " & _
        pohon.Nama & vbCrLf & "Usia pohon adalah " & pohon.Usia & vbCrLf & _
        vbCrLf

        ' menampilkan informasi orang
        keluaran &= orang.ToString() & ": " & _
        orang.Nama & vbCrLf & "Usia orang adalah " & orang.Usia & _
        vbCrLf

        Dim referensiUsia As IUsia

        ' menampilkan nama dan usia untuk tiap objek IUsia di dalam iArrayUsia
        For Each referensiUsia In iArrayUsia
            keluaran &= vbCrLf & referensiUsia.Nama & ": " & _
            "Usia adalah " & referensiUsia.Usia
        Next

        MessageBox.Show(keluaran, "Demonstrasi Polimorfisme")
    End Sub ' Main

End Class ' CUji



Gambar 9.4 Keluaran program pada kode 9.18

Pada contoh selanjutnya akan diuji kembali hirarki CTitik-CLingkaran-CSilinder menggunakan sebuah antarmuka, menggantikan penggunaan kelas abstrak. Sekarang akan ditunjukkan bagaimana sebuah kelas dapat mengimplementasikan antarmuka, kemudian berperan sebagai kelas basis untuk kelas-kelas terderivasi untuk mewawariskan implementasi. Antarmuka IBangun (kode 9.19) akan diciptakan, yang menspesifikasi metode Luas dan Volume dan properti Nama (baris 7-9). Setiap kelas yang mengimplementasikan antarmuka IBangun harus menyediakan implementasi atas kedua implementasi dan properti.

Karena kelas CTitik3 (kode 9.20) mengimplementasikan antarmuka IBangun, kelas CTitik3 harus mengimplementasikan ketiga anggota IBangun. Baris 55-59 mengimplementasikan metode Luas, yang menghasilkan 0, karena titik memiliki luas nol. Baris 62-66 mengimplementasikan metode Volume, yang juga menghasilkan 0, karena titik memiliki volume nol. Baris 69-76 mengimplementasikan properti ReadOnly, Nama, yang menghasilkan nama kelas sebagai sebuah String (“CTitik3”). Perhatikan bahwa penyertaan katakunci Implements diikuti dengan nama metode/properti antarmuka di dalam implementasi metode/properti. Katakunci tersebut menginformasikan kompiler bahwa setiap metode/properti adalah implementasi dari metode/properti antarmuka terkait. Juga perhatikan bahwa kelas CTitik3 menspesifikasi metode/properti sebagai Overridable, yang memampukan kelas terderivasi mendefinisikan-ulang metode/properti tersebut.

Ketika sebuah kelas mengimplementasikan antarmuka, kelas memiliki relasi “adalah suatu” seperti yang dimiliki pewarisan. Pada contoh ini, kelas CTitik3 mengimplementasikan antarmuka IBangun. Oleh karena itu, objek CTitik3 adalah suatu IBangun, dan objek-objek dari sembarang kelas yang mewarisi CTitik3 adalah juga objek IBangun. Sebagai contoh, kelas CLingkaran3 (kode 9.21) mewarisi kelas CTitik3; jadi, sebuah CLingkaran3 adalah suatu IBangun. Kelas CLingkaran3 mengimplementasikan antarmuka IBangun secara implisit, karena kelas CLingkaran3 mewarisi metode-metode IBangun yang diimplementasikan oleh CTitik. Karena lingkaran tidak memiliki volume, kelas CLingkaran3 mewarisi metode Volume dari kelas CTitik3, yang menghasilkan nol. Namun, Anda tentu tidak ingin menggunakan metode Luas atau properti Nama dari kelas CTitik3 untuk kelas CLingkaran3. Kelas CLingkaran3 harus menyediakan implementasi sendiri untuk metode dan properti tersebut, karena luas dan nama sebuah lingkaran berbeda dari sebuah titik. Baris 51-53 mendefinisikan-ulang metode Luas untuk menghasilkan luas lingkaran, dan baris 56-62 mendefinisikan-ulang properti Nama untuk menghasilkan  StringCLingkaran3”.

Kelas CSilinder3 (kode 9.22) mewarisi kelas CLingkaran3. Kelas CSilinder3 mengimplementasikan antarmuka IBangun secara implisit, karena kelas CSilinder3 mewarisi Luas dan properti Nama dari kelas CLingkaran3 dan metode Volume dari kelas CTitik3. Namun, kelas CSilinder3 mendefinisikan-ulang properti Nama dan metode Luas dan Volume untuk melakukan operasi-operasi yang spesifik untuk CSilinder3. Baris 43-45 mendefinisikan-ulang metode Luas untuk menghasilkan luas permukaan silinder, baris 48-50 mendefinisikan-ulang metode Volume untuk menghasilkan volume silinder dan baris 58-64 mendefinisikan-ulang properti Nama untuk menghasilkan StringCSilinder3”.

1
2
3
4
5
6
7
8
9
10
11
' Kode 9.19: Bangun.vb
' Antarmuka IBangun untuk hirarki Titik, Lingkaran, dan Silinder.

Public Interface IBangun

    ' kelas-kelas yang mengimplementasikan IBangun harus mendefinisikan metode/properti ini
    Function Luas() As Double
    Function Volume() As Double
    ReadOnly Property Nama() As String

End Interface ' IBangun

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
' Kode 9.20: Titik3.vb
' kelas CTitik3 mengimplementasikan IBangun.

Public Class CTitik3
    Implements IBangun ' CTitik3 mewarisi antarmuka IBangun

    ' koordinat titik
    Private mX, mY As Integer

    ' konstruktor default
    Public Sub New()
        X = 0
        Y = 0
    End Sub ' New

    ' konstruktor
    Public Sub New(ByVal xNilai As Integer, _
        ByVal yNilai As Integer)
        X = xNilai
        Y = yNilai
    End Sub ' New

    ' properti X
    Public Property X() As Integer

        Get
            Return mX
        End Get

        Set(ByVal xNilai As Integer)
            mX = xNilai ' tidak perlu validasi
        End Set

    End Property ' X

    ' properti Y
    Public Property Y() As Integer

        Get
            Return mY
        End Get

        Set(ByVal yNilai As Integer)
            mY = yNilai ' tidak perlu validasi
        End Set

    End Property ' Y

    ' menghasilkan representasi String atas CTitik3
    Public Overrides Function ToString() As String
        Return "[" & mX & ", " & mY & "]"
    End Function ' ToString

    ' implementasi metode Luas antarmuka IBangun
    Public Overridable Function Luas() As Double _
    Implements IBangun.Luas

        Return 0
    End Function ' Luas

    ' implementasi metode Volume antarmuka IBangun
    Public Overridable Function Volume() As Double _
    Implements IBangun.Volume

        Return 0
    End Function ' Volume

    ' implementasi properti Nama antarmuka IBangun
    Public Overridable ReadOnly Property Nama() As String _
    Implements IBangun.Nama

        Get
            Return "CTitik3"
        End Get

    End Property ' Nama

End Class ' CTitik3

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
' Kode 9.21: Lingkaran3.vb
' Kelas CLingkaran3 mewarisi kelas CTitik3 dan mendefinisikan-ulang beberapa metodenya

Public Class CLingkaran3
    Inherits CTitik3 ' CLingkaran3 mewarisi kelas CTitik3

    Private mRadius As Double ' radius CLingkaran3

    ' konstruktor default
    Public Sub New()
        Radius = 0
    End Sub ' New

    ' konstruktor
    Public Sub New(ByVal xNilai As Integer, _
        ByVal yNilai As Integer, ByVal nilaiRadius As Double)

        ' menggunakan referensi MyBase ke konstruktor CTitik3 secara eksplisit
        MyBase.New(xNilai, yNilai)
        Radius = nilaiRadius
    End Sub ' New

    ' properti Radius
    Public Property Radius() As Double

        Get
            Return mRadius
        End Get

        Set(ByVal nilaiRadius As Double)

            If nilaiRadius > 0 Then
                mRadius = nilaiRadius  ' mRadius tidak bisa bernilai nagatif
            End If

        End Set

    End Property ' Radius

    ' menghitung diameter CLingkaran3
    Public Function Diameter() As Double
        Return mRadius * 2
    End Function ' Diameter

    ' menghitung keliling CLingkaran3
    Public Function Keliling() As Double
        Return Math.PI * Diameter()
    End Function ' Keliling

    ' menghitung luas CLingkaran3
    Public Overrides Function Luas() As Double
        Return Math.PI * mRadius ^ 2
    End Function ' Luas

    ' mendefinisikan-ulang properti Nama antarmuka IBangun dari kelas CTitik3
    Public Overrides ReadOnly Property Nama() As String

        Get
            Return "CLingkaran3"
        End Get

    End Property ' Nama

    ' menghasilkan representasi String atas CLingkaran3
    Public Overrides Function ToString() As String

        ' menggunakan referensi MyBase untuk menghasilkan representasi String CLingkaran3
        Return "Pusat= " & MyBase.ToString() & _
        "; Radius = " & mRadius
    End Function ' ToString

End Class ' CLingkaran3

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
' Kode 9.22: Silinder3.vb
' Kelas CSilinder3 mewarisi kelas CLingkaran3 dan mendefinisikan-ulang beberapa anggota.

Public Class CSilinder3
    Inherits CLingkaran3  ' CSilinder3 mewarisi kelas CLingkaran3

    Protected mTinggi As Double

    ' konstruktor default
    Public Sub New()
        Tinggi = 0
    End Sub ' New

    ' konstruktor empat-argumen
    Public Sub New(ByVal xNilai As Integer, _
        ByVal yNilai As Integer, ByVal nilaiRadius As Double, _
        ByVal nilaiTinggi As Double)

        ' pemanggilan eksplisit terhadap konstruktor CLingkaran3
        MyBase.New(xNilai, yNilai, nilaiRadius)
        Tinggi = nilaiTinggi ' menetapkan tinggi CSilinder2
    End Sub ' New

    ' properti Tinggi
    Public Property Tinggi() As Double

        Get
            Return mTinggi
        End Get

        ' menetapkan tinggi CSilinder3 jika nilai argumen positif
        Set(ByVal nilaiTinggi As Double)

            If nilaiTinggi >= 0 Then
                mTinggi = nilaiTinggi
            End If

        End Set

    End Property ' Tinggi

    ' mendefinisikan-ulang Luas untuk menghitung luas CSilinder3
    Public Overrides Function Luas() As Double
        Return 2 * MyBase.Luas + MyBase.Keliling * mTinggi
    End Function ' Luas

    ' menghitung volume CSilinder3
    Public Overrides Function Volume() As Double
        Return MyBase.Luas * mTinggi
    End Function ' Volume

    ' mengkonversi CSilinder3 menjadi String
    Public Overrides Function ToString() As String
        Return MyBase.ToString() & "; Tinggi = " & mTinggi
    End Function ' ToString

    ' mendefinisikan-ulang properti Nama dari kelas CLingkaran3
    Public Overrides ReadOnly Property Nama() As String

        Get
            Return "CSilinder3"
        End Get

    End Property ' Nama

End Class ' CSilinder3

Kelas CUji3 (kode 9.23) mendemonstrasikan hirarki titik-lingkaran-silinder yang menggunakan antarmuka. Kelas CUji3 hanya memiliki dua perbedaan dari kode 9.8, yang menguji hirarki kelas yang diciptakan dari kelas basis MustInherit, CBangun. Pada kode 9.23, baris 16 mendeklarasikan arrayBangun sebagai sebuah array yang memuat beberapa referensi antarmuka IBangun. Pada kode 9.8, beberapa pemanggilan terhadap metode ToString dilakukan melalui referensi kelas basis CBangun, tetapi, karena antarmuka IBangun tidak menyediakan metode ToString, klien tidak dapat memanggil metode ToString pada tiap objek IBangun.

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
' Kode 9.23: Uji3.vb
' Demonstrasi polimorfisme dalam hirarki Titik-Lingkaran-Silinder.

Imports System.Windows.Forms

Class CUji3

    Shared Sub Main()

        ' instansiasi objek CTitik3, CLingkaran3, dan CSilinder3
        Dim titik As New CTitik3(7, 11)
        Dim lingkaran As New CLingkaran3(22, 8, 3.5)
        Dim silinder As New CSilinder3(10, 10, 3.3, 10)

        ' instansiasi array yang memuat beberapa referensi kelas basis
        Dim arrayBangun(2) As IBangun

        ' arrayBangun(0) mereferensi objek CTitik3
        arrayBangun(0) = titik

        ' arrayBangun(1) mereferensi objek CLingkaran3
        arrayBangun(1) = lingkaran

        ' arrayBangun(2) mereferensi objek CSilinder3
        arrayBangun(2) = silinder

        Dim keluaran As String = titik.Nama & ": " & _
        titik.ToString() & vbCrLf & lingkaran.Nama & ": " & _
        lingkaran.ToString() & vbCrLf & silinder.Nama & _
        ": " & silinder.ToString()

        Dim bangun As IBangun

        ' menampilkan nama, luas, dan volume untuk tiap objek di
        ' dalam arrayBangun
        For Each bangun In arrayBangun
            keluaran &= vbCrLf & vbCrLf & bangun.Nama & ": " & _
            vbCrLf & "Luas = " & _
            String.Format("{0:F}", bangun.Luas) & vbCrLf & _
            "Volume = " & String.Format("{0:F}", bangun.Volume)
        Next

        MessageBox.Show(keluaran, "Demonstrasi Polimorfisme")
    End Sub ' Main

End Class ' CUji3



Gambar 9.5 Keluaran program pada kode 9.23


Delegate
Pada Bab 5, telah didiskusikan bagaimana objek dapat melewatkan variabel anggota sebagai argumen kepada metode. Namun, kadangkala, lebih menguntungkan bagi objek untuk melewatkan metode sebagai argumen kepada metode lainnya. Sebagai contoh, misalnya Anda ingin mengurutkan sederet nilai dalam urutan menaik dan urutan menurun. Daripada harus menyediakan dua metode terpisah untuk mengurutkan menaik dan mengurutkan menurun, Anda dapat menggunakan satu metode yang menerima sebagai argumen sebuah referensi yang menunjuk ke metode perbandingan yang digunakan. Untuk melakukan pengurutan menaik, Anda dapat melewatkan referensi metode pengurut kepada metode perbandingan-pengurutan-menaik;  Untuk melakukan pengurutan menurun, Anda dapat melewatkan referensi metode pengurut kepada metode perbandingan-pengurutan-menurun. Metode pengurut kemudian akan menggunakan referensi ini untuk mengurutkan sederet nilai.

Visual Basic tidak mengijinkan pelewatan referensi metode secara langsung sebagai argumen kepada metode lain, tetapi menyediakan delegate, yang merupakan kelas yang mengenkapsulasi himpunan referensi yang menunjuk ke metode. Sebuah objek delegate yang memuat referensi-referensi metode dapat dilewatkan kepada metode lain. Daripada mengirimkan referensi metode secara langsung, sebuah objek dapat mengirimkan instans delegate, yang memuat referensi metode. Metode yang menerima referensi, yang menunjuk ke delegate, kemudian dapat memanggil metode yang dimuat di dalam delegate.

Delegate yang memuat satu metode dikenal dengan delegate singlecast dan diciptakan atau diderivasi dari kelas Delegate. Delegate yang memuat banyak metode dikenal dengan delegate multicast dan diciptakan atau diderivasi dari kelas MulticastDelegate. Kedua jenia delegate berada di dalam namespace System.

Untuk menggunakan delegate, Anda harus mendeklarasikannya lebih dahulu. Deklarasi delagate menspesifikasi sidik metode (parameter dan nilai balik). Metode, dengan referensi yang akan dimuat di dalam objek delegate, harus memiliki sidik metode yang sama dengan yang didefinisikan di dalam deklarasi delagate. Anda kemudian menciptakan metode yang memiliki sidik ini. Langkah ketiga adalah menciptakan instans delegate via katakunci AddressOf. Setelah instans delegate diciptakan, Anda dapat memanggil referensi metode yang dimuatnya. Proses ini akan ditunjukkan pada contoh berikutnya.

Kelas CUrutBubbleDelegate (kode 9.24), yang dimodifikasi dari contoh pengurutan-bubble pada Bab 6, menggunakan beberapa delaget untuk mengurutkan sebuah array Integer dengan urutan menaik atau urutan menurun. Baris 7-9 menyediakan deklarasi untuk delegate Komparator. Untuk mendeklarasikan sebuah delegate (baris 7), Anda mendeklarasikan sidik suatu metode, dimana katakunci Delegate ditempatkan setelah pemodifikasi akses-anggota (pada kasus ini, Public), diikuti dengan katakunci Function (atau katakunci Sub), nama delegate, daftar parameter, dan tipe nilai balik. Delegate Komparator mendefinisikan suatu sidik metode untuk metode yang menerima dua argumen Integer dan yang menghasilkan nilai balik Boolean. Perhatikan bahwa delegate Komparator tidak memiliki tubuh. Seperti yang akan didemonstrasikan, aplikasi ini (kode 9.25) mengimplementasikan metode yang sesuai dengan sidik delegate Komparator, kemudian melewatkan metode tersebut (sebagai argumen bertipe Komparator) kepada metode UrutArray. Perhatikan bahwa Anda mendeklarasikan delegate Komparator sebagai sebuah Function, karena ia menghasilkan nilai balik (bertipe Boolean).

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
' Kode 9.24: UrutBubbleDelegate.vb
' Uses delegates to sort random numbers (ascending or descending).

Public Class CUrutBubbleDelegate

    ' definisi delegate
    Public Delegate Function Komparator( _
        ByVal elemen1 As Integer, _
        ByVal elemen2 As Integer) As Boolean

    ' mengurutkan array tergantung dari komparator
    Public Sub UrutArray(ByVal array() As Integer, _
        ByVal Banding As Komparator)

        Dim i, pass As Integer

        For pass = 0 To array.Length - 1

            ' perbandingan loop sebelah dalam
            For i = 0 To array.Length - 2

                If Banding(array(i), array(i + 1)) Then
                    Tukar(array(i), array(i + 1))
                End If

            Next ' loop sebelah dalam

        Next ' loop sebelah luar

    End Sub ' UrutArray

    ' menukar dua elemen
    Private Sub Tukar(ByRef elemenPertama As Integer, _
        ByRef elemenKedua As Integer)

        Dim tampung As Integer

        tampung = elemenPertama
        elemenPertama = elemenKedua
        elemenKedua = tampung
    End Sub ' Tukar

End Class ' CUrutBubbleDelegate

Baris 12-30 mendefinisikan metode UrutArray, yang mengambil sebuah argumen dan sebuah referensi yang menunjuk ke Komparator sebagai argumen. Metode UrutArray memodifikasi array dengan mengurutkan isinya. Baris 22 menggunakan metode delegate dalam menentukan bagaimana mengurutkan array. Baris 22 memanggil metode yang diapit di dalam objek delegate dengan memperlakukan referensi delegate sebagai metode yang dimuat objek delegate. Visual Basic memanggil referensi metode yang diapit secara langsung, melewatkan padanya parameter array(i) dan array(i+1). Komparator menentukan tipe pengurutan untuk kedua argumennya. Untuk mengurutkan secara menaik, Komparator akan menghasilkan True ketika elemen pertama yang sedang dibandingkan lebih besar dari elemen kedua. Sama halnya, untuk mengurutkan secara menurun, Komparator menghasilkan True ketika elemen pertama yang sedang dibandingkan lebih kecil dari elemen kedua.

Kelas CFrmUrutBubble (kode 9.25) menampilkan sebuah Form dengan dua kotak teks dan tiga tombol. Kotak teks pertama menampilkan sederet angka tak-terurut, dan kotak teks kedua menampilkan sederet angka yang telah diurutkan. Tombol Ciptakan Data menciptakan sederet nilai yang tak-terurut. Tombol Urutkan Menaik dan Urutkan Menurun mengurutkan array dengan urutan menaik dan menurun. Metode UrutMenaik (baris 31-35) dan UrutMenurun (baris 38-42) masing-masing memiliki sebuah sidik yang berkaitan dengan sidik yang didefinisikan oleh deklarasi delegate Komparator (yaitu, masing-masing menerima dua Integer dan menghasilkan nilai balik Boolean). Seperti yang Anda akan lihat, program melewatkan kepada CUrutBubble-Delegate dua delegate UrutArray yang memuat dua referensi yang menunjuk ke UrutMenaik dan UrutMenurun, yang akan menentukan watak pengurutan CUrutBubbleDelegate.

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
' Kode 9.25: FrmUrutBubble.vb
' Menciptakan GUI yang memampukan pengguna dalam mengurutkan array.

Imports System.Windows.Forms

Public Class CFrmUrutBubble
    Inherits Form

    ' TextBox yang memuat sederet nilai awal
    Friend WithEvents txtAsli As TextBox
    Friend WithEvents lblAsli As Label

    ' TextBox yang memuat sederet nilai yang telah terurut
    Friend WithEvents txtTerurut As TextBox
    Friend WithEvents lblTerurut As Label

    ' Button untuk menciptakan dan mengurutkan sederet nilai
    Friend WithEvents cmdCiptakan As Button
    Friend WithEvents cmdUrutkanMenaik As Button
    Friend WithEvents cmdUrutkanMenurun As Button

    ' kode yang dibangkitkan oleh Windows Form Designer

    ' referensi yang menunjuk ke objek yang memuat delegate
    Dim mUrutBubble As New CUrutBubbleDelegate()

    ' array asli dengan elemen-elemen tak-terurut
    Dim mElemenArray(9) As Integer

    ' implementasi delegate pengurutan secaran menaik
    Private Function UrutMenaik(ByVal elemen1 As Integer, _
        ByVal elemen2 As Integer) As Boolean

        Return elemen1 > elemen2
    End Function ' UrutMenaik

    ' implementasi delegate pengurutan secara menurun
    Private Function UrutMenurun(ByVal elemen1 As Integer, _
        ByVal elemen2 As Integer) As Boolean

        Return elemen1 < elemen2
    End Function ' UrutMenurun

    ' menciptakan sederet nilai secara acak
    Private Sub cmdCiptakan_Click(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles cmdCiptakan.Click

        txtTerurut.Clear()

        Dim keluaran As String
        Dim angkaAcak As Random = New Random()
        Dim i As Integer

        ' menciptakan String dengan 10 angka acak
        For i = 0 To mElemenArray.Length - 1
            mElemenArray(i) = angkaAcak.Next(100)
            keluaran &= mElemenArray(i) & vbCrLf
        Next

        txtAsli.Text = keluaran ' menampilkan angka-angka

        ' mengaktifkan tombol pengurutan
        cmdUrutkanMenaik.Enabled = True
        cmdUrutkanMenurun.Enabled = True
    End Sub  ' cmdCiptakan_Click

    ' menampilkan isi array di dalam TextBox tertentu
    Private Sub TampilHasil()

        Dim keluaran As String
        Dim i As Integer

        ' menciptakan string dengan sederet angka terurut
        For i = 0 To mElemenArray.Length - 1
            keluaran &= mElemenArray(i) & vbCrLf
        Next

        txtTerurut.Text = keluaran ' menampilkan angka-angka
    End Sub ' TampilHasil

    ' mengurutkan sederet nilai secara menaik
    Private Sub cmdUrutkanMenaik_Click(ByVal sender As  _
        System.Object, ByVal e As System.EventArgs) _
        Handles cmdUrutkanMenaik.Click

        ' mengurutkan array
        mUrutBubble.UrutArray(mElemenArray, AddressOf UrutMenaik)

        TampilHasil() ' menampilkan hasil

        cmdUrutkanMenaik.Enabled = False
        cmdUrutkanMenurun.Enabled = True
    End Sub  ' cmdUrutkanMenaik_Click

    ' mengurutkan sederet nilai secara menurun
    Private Sub cmdUrutkanMenurun_Click(ByVal sender As  _
        System.Object, ByVal e As System.EventArgs) _
        Handles cmdUrutkanMenurun.Click

        ' mengurutkan objek dan mengurutkan array
        mUrutBubble.UrutArray(mElemenArray, AddressOf UrutMenurun)

        TampilHasil() ' menampilkan hasil

        cmdUrutkanMenaik.Enabled = False
        cmdUrutkanMenurun.Enabled = True
    End Sub  ' cmdUrutkanMenurun_Click

End Class  ' CFrmUrutBubble



Gambar 9.6 Keluaran program pada kode 9.25


Latihan
1.       Modifikasilah sistem penggajian pada kode 9.10 – 9.14 dan tambahkan dua variabel instans Private, yaitu mTanggalLahir (menggunakan kelas CHari dari kode 7.8) dan mKode-Departemen (sebuah Integer) kepada kelas CKaryawan. Asumsikan bahwa penggajian diproses sekali dalam sebulan. Ciptakan sebuah array yang memuat beberapa referensi CKaryawan untuk menyimpan pelbagai objek karyawan. Menggunakan sebuah loop, hitung penggajian untuk tiap CKaryawan (secara polimorfik).

2.       Implementasikan hirarki CBangun yang ditampilkan pada Gambar 8.3. Setiap CBangun-DuaDimensi harus memuat metode Luas untuk menghitung luas bangun dua dimensi. Setiap CBangunTigaDimensi harus memuat metode Luas dan Volume untuk menghitung luas permukaan dan volume bangun tiga dimensi. Ciptakan program yang menggunakan sebuah array yang memuat beberapa referensi CBangun yang menunjuk ke setiap kelas konkrit di dalam hirarki. Program harus menampikan representasi String untuk tiap objek di dalam array. Di samping itu, di dalam loop yang memproses semua bangun di dalam array, tentukan apakah suatu bangun adalah sebuah CBangunDuaDimensi atau sebuah CBangunTigaDimensi. Jika suatu bangun adalah CBangunDuaDimensi, maka tampilkan Luasnya. Jika suatu bangun adalah CBangunTigaDimensi, maka tampilkan Luas dan Volumenya.











No comments:

Post a Comment