Sebelumnya
Kami hampir mencapai akhir perjalanan kami melalui putaran bonus Pengenalan Pemrograman Berorientasi Objek kami! Dalam artikel terakhir kami, kami memulai contoh Petting Zoo dengan ulasan kelas, objek, dan metode. Jika Anda melewatkan awal seri ini, Anda dapat mengejar ketinggalan dengan kami di sini. Jika tidak, mari selami kembali!
.
Konstruktor
Jika Anda melakukan latihan dengan dua Dog
objek, itu agak membosankan, kan? Lagi pula, kita tidak memiliki apa pun untuk memisahkan anjing satu sama lain dan tidak ada cara untuk mengetahui, tanpa melihat kode sumber, anjing mana yang menghasilkan dan menggonggong.
Pada artikel sebelumnya, saya menyebutkan bahwa ketika Anda membuat objek, Anda memanggil metode khusus yang disebut konstruktor . Konstruktor terlihat seperti nama kelas yang ditulis sebagai metode. Misalnya, untuk Dog
kelas, konstruktor akan disebut Dog()
.
Hal khusus tentang konstruktor adalah bahwa mereka adalah jalur ke objek baru apa pun, jadi mereka adalah tempat yang bagus untuk memanggil kode yang menginisialisasi objek dengan nilai default. Selanjutnya, nilai kembalian dari metode konstruktor selalu merupakan objek dari kelas itu sendiri, itulah sebabnya kami dapat menetapkan nilai kembalian konstruktor ke variabel dari tipe kelas yang kami buat.
Namun, sejauh ini, kita belum benar-benar membuat konstruktor, jadi kenapa kita masih bisa memanggil metode itu?
Dalam banyak bahasa, termasuk C#, bahasa ini memberi Anda konstruktor gratis dan kosong tanpa Anda harus melakukan apa pun. Tersirat bahwa Anda menginginkan konstruktor; jika tidak, tidak akan ada cara untuk menggunakan kelas untuk apa pun, jadi bahasa hanya menganggap bahwa Anda telah menulisnya.
Konstruktor yang tidak terlihat dan gratis ini disebut konstruktor default , dan, dalam contoh kita, akan terlihat seperti ini:
public Dog(){ }
Perhatikan bahwa sintaks ini sangat mirip dengan Speak()
metode yang kami buat sebelumnya, kecuali bahwa kami tidak secara eksplisit mengembalikan nilai atau bahkan mendeklarasikan tipe pengembalian metode. Seperti yang saya sebutkan sebelumnya, konstruktor selalu mengembalikan instance dari kelas tempatnya berada.
Dalam hal ini, itu adalah kelas Dog
, dan itulah sebabnya ketika kita menulis Dog myDog = new Dog()
, kita dapat menetapkan objek baru ke variabel bernama myDog yang bertipe Dog
.
Jadi mari tambahkan konstruktor default ke Dog
kita kelas. Anda dapat menyalin baris di atas atau, di Visual Studio, Anda dapat menggunakan pintasan:ketik ctor
dan tekan Tab
dua kali. Ini harus menghasilkan konstruktor default untuk Anda, seperti yang ditunjukkan pada Gambar 9:
Gambar 9:Menambahkan Konstruktor dengan ‘ctor’
Konstruktor default sebenarnya tidak memberi kita sesuatu yang baru karena sekarang secara eksplisit melakukan apa yang dilakukan secara implisit sebelumnya. Namun, ini adalah metode, jadi sekarang kita dapat menambahkan konten di dalam tanda kurung yang akan dieksekusi setiap kali kita memanggil konstruktor ini. Dan karena konstruktor berjalan sebagai hal pertama dalam konstruksi objek, itu adalah tempat yang tepat untuk menambahkan kode inisialisasi.
Misalnya, kita dapat mengatur Name
properti objek kita ke sesuatu dengan menambahkan kode seperti ini:
public Dog() { this.Name = "Snoopy"; }
Contoh ini akan mengatur Name
properti objek baru apa pun ke "Snoopy".
Tentu saja, itu tidak terlalu berguna karena tidak semua anjing disebut “Snoopy”, jadi sebagai gantinya, mari kita ubah tanda tangan metode konstruktor sehingga menerima parameter.
Tanda kurung metode tidak hanya ada untuk terlihat cantik; mereka berfungsi untuk memuat parameter yang dapat kita gunakan untuk meneruskan nilai ke suatu metode. Fungsi ini berlaku untuk semua metode, bukan hanya konstruktor, tetapi mari kita lakukan untuk konstruktor terlebih dahulu.
Ubah tanda tangan konstruktor default menjadi ini:
public Dog(string dogName)
Penambahan ini memungkinkan kita untuk mengirim string
parameter ke dalam konstruktor, dan ketika kita melakukannya, kita dapat merujuk ke parameter itu dengan nama dogName
.
Kemudian, tambahkan baris berikut ke blok metode:
this.Name = dogName;
Baris ini menetapkan properti objek ini Name
ke parameter yang kami kirim ke konstruktor.
Perhatikan bahwa ketika Anda mengubah tanda tangan konstruktor, Anda mendapatkan kasus coretan merah di file Program.cs Anda, seperti yang ditunjukkan pada Gambar 10.
Gambar 10:Kasus Squigglies Merah dari Konstruktor Baru Kami
Saat kita menambahkan konstruktor eksplisit kita sendiri, C# dan .NET tidak akan secara implisit membuat konstruktor default untuk kita. Dalam file Program.cs kami, kami masih membuat Dog
objek menggunakan konstruktor tanpa parameter default, yang sekarang tidak ada lagi.
Untuk memperbaiki masalah ini, kita perlu menambahkan parameter ke panggilan konstruktor kita di Program.cs. Kita dapat, misalnya, memperbarui garis konstruksi objek kita sebagai berikut:
Anjing myDog =Anjing baru(“Snoopy”);
Melakukannya akan menghapus coretan merah dan memungkinkan Anda untuk menjalankan kode lagi. Jika Anda meninggalkan atau menyetel breakpoint setelah baris kode terakhir, Anda dapat melihat panel Locals dan memverifikasi bahwa Name
objek Anda properti memang telah ditetapkan, seperti yang ditunjukkan pada Gambar 11.
Gambar 11:Melihat Nama Properti Kita Diset dengan Benar
Mengerti? Bagus! Kami sekarang memiliki kemampuan untuk menamai anjing kami, tetapi itu bukan program yang benar-benar berguna jika orang harus men-debugnya untuk melihat apa yang kami lakukan. Jadi mari kita campur kodenya sedikit untuk memastikan bahwa kita menampilkan nama anjing yang menggonggong.
Perbarui Dog
. Anda objek dan ubah Speak()
metode seperti:
public void Speak() { Console.WriteLine(this.Name + " says: Woof"); }
Perubahan yang kita buat sekarang memberitahu WriteLine
metode untuk menggabungkan nama objek ini dengan string literal " mengatakan:Woof" yang seharusnya memberi kita output yang lebih baik menampilkan upaya kita. Coba jalankan programnya sekarang, dan Anda akan melihat sesuatu seperti Gambar 12.
Gambar 12:Snoopy Mengatakan:Woof
Kerja bagus! Sekarang Anda dapat membuat banyak anjing dengan nama berbeda, dan mereka semua akan menggonggong sesuai perintah Anda.
Tentu saja, kebun binatang dengan anjing saja agak membosankan. Maksudku, aku suka anjing, tapi mungkin kita bisa menambahkan beberapa hewan tambahan untuk sedikit menambah pengalaman?
.
Warisan
Mari kita mulai dengan menambahkan Cat
baru kelas ke file Animals.cs kami. Tambahkan kode berikut di sebelah kelas Dog, tetapi masih di dalam kurung namespace PettingZoo:
class Cat { public Cat(string catName) { this.Name = catName; } string Name; public void Speak() { Console.WriteLine(this.Name + " says: Meow!"); } }
Lalu, mari kita buat Cat
objek di Program.cs dan membuatnya berbicara:
Cat myCat = new Cat("Garfield"); myCat.Speak();
Menjalankan program ini sekarang akan memberikan output yang menyerupai Gambar 13.
Gambar 13:Garfield Mengatakan:Meow
Program kami dapat diprediksi dan berfungsi, tetapi apakah Anda memperhatikan betapa miripnya kedua kelas itu? Lihat berapa banyak kode yang telah kami duplikat di dua kelas? Bukankah orientasi objek seharusnya menyelamatkan kita dari penulisan kode berkali-kali?
Jawabannya iya. Kita dapat–dan harus–menyederhanakan kode ini untuk mengurangi jumlah duplikasi. Apa yang akan kita bahas akan mendemonstrasikan fitur OO yang disebut warisan .
Warisan dalam orientasi objek memungkinkan Anda membuat hierarki kelas dan membuat setiap kelas mewarisi properti dan metode kelas induk. Misalnya, untuk kebun binatang kita, kita dapat membuat Animal
induknya kelas dan memiliki Dog
dan Cat
mewarisi dari kelas itu. Kemudian, kita dapat memindahkan bagian dari kode kita ke dalam Animal
kelas sehingga keduanya Dog
dan Cat
kelas akan mewarisi kode itu.
Namun, jika kita memindahkan bagian duplikat dari kode kita ke Animal
kelas, lalu Dog
dan Cat
kelas masing-masing akan mewarisi properti dan metode yang sama, membuat anak-anak klon dari kelas induk. Organisasi ini tidak terlalu berguna karena kami ingin memiliki jenis hewan yang berbeda. Akan sangat membosankan jika kucing, anjing, dan semua hewan lainnya sama. Faktanya, untuk tujuan program kami, tidak masuk akal untuk menyebut mereka sebagai hal yang berbeda sama sekali.
Sekarang, jika pewarisan berarti bahwa kita hanya dapat membuat kelas anak yang identik dengan kelas induknya, tidak ada gunanya melakukan semua upaya ini. Jadi, sementara kita mewarisi semua bagian dari kelas induk, kita juga dapat mengganti bagian tertentu dari kelas induk di kelas turunan untuk membuat kelas turunan menjadi berbeda.
Mari kita lihat ini dan lihat cara kerjanya, ya?
.
Membuat Kelas Induk dan Anak
Kita akan mundur beberapa langkah dan membuat ulang Dog
dan Cat
kelas dengan cara yang lebih baik. Untuk memulai, kita memerlukan kelas induk yang akan mendefinisikan properti dan metode bersama dari kelas turunan.
Di file Animals.cs Anda, hapus Dog
dan Cat
kelas dan tambahkan definisi kelas berikut:
class Animal { public string Name; public string Sound; public void Speak() { Console.WriteLine(this.Name + " says " + this.Sound); } }
Kelas ini terlihat tidak mengejutkan seperti Dog
sebelumnya dan Cat
kelas, dengan pengecualian yang dicatat bahwa kami telah membuat semua properti dan metode menjadi publik dan bahwa kami telah memperkenalkan properti baru yang disebut Suara bertipe string
. Akhirnya, kami telah memperbarui Speak
metode untuk menggunakan Suara variabel.
Pada titik ini, Program.cs Anda tidak akan berfungsi dan, jika Anda mengklik tab itu, Anda akan melihat beberapa pesan kesalahan, yang wajar saja karena kami telah menghapus Cat
dan Dog
kelas. Mari kita buat ulang dan lakukan dengan menggunakan warisan. Di file Animals.cs Anda, tepat setelah Animal
kelas, tambahkan kode berikut:
class Dog : Animal { } class Cat : Animal { }
Kelas baru ini jauh lebih pendek dari sebelumnya dan tidak mereplikasi kode apa pun. Sintaks baru di sini adalah titik dua diikuti dengan nama kelas Animal
, yang memberi tahu C# bahwa kita menginginkan keduanya Dog
dan Cat
untuk mewarisi dari Animal
kelas. Akibatnya, Dog
dan Cat
menjadi kelas anak Animal
seperti yang diilustrasikan dalam diagram yang ditunjukkan pada Gambar 14.
Gambar 14:Diagram Pewarisan Kelas Hewan
Catatan:Saya telah menggunakan istilah Properti sejauh ini, yang sedikit tidak akurat karena istilah yang benar adalah bidang seperti yang Anda lihat pada diagram di Gambar 14. Namun, bidang kurang jelas di luar lingkup pemrograman, jadi saya menggunakan Properti sebagai gantinya. Secara teknis, properti adalah pembungkus di sekitar bidang di C#.
.
Kami masih memiliki masalah dengan file Program.cs kami, karena konstruktor khusus yang kami buat. Jika Anda mencoba menjalankan atau men-debug program kami, maka Anda akan melihat pesan kesalahan yang mengatakan bahwa "'PettingZoo.Cat' tidak mengandung konstruktor yang membutuhkan 1 argumen" dan yang serupa untuk "PettingZoo.Dog".
Untuk memperbaiki kesalahan ini, kita perlu menambahkan kembali konstruktor. Namun kali ini, kita akan menggunakan warisan untuk mewarisi konstruktor dan menunjukkan bagaimana Anda dapat memperluas konstruktor untuk mengubah fungsionalitas kelas induk.
Pertama, kita perlu membuat konstruktor dasar untuk Animal
, yang akan menyerupai konstruktor sebelumnya yang kita buat sebelumnya. Tambahkan kode berikut ke Animal
. Anda kelas:
public Animal(string animalName) { this.Name = animalName; }
Seperti sebelumnya, konstruktor kami menetapkan nama hewan untuk apa yang kami berikan ke dalamnya. Namun, ini tidak cukup karena kita juga perlu menambahkan konstruktor ke Dog
dan Cat
kelas. Kami akan menggunakan ini untuk menentukan suara yang dihasilkan setiap hewan juga.
class Dog : Animal { public Dog(string dogName) : base(dogName) { this.Sound = "Woof"; } } class Cat : Animal { public Cat(string catName) : base(catName) { this.Sound = "Meow"; } }
Untuk kedua kelas, kami menambahkan konstruktor yang menerima Name
parameter. Kami juga mengatur Sound
objek ini properti untuk suara yang kita inginkan dari hewan tersebut.
Namun, tidak seperti sebelumnya, sekarang kita memanggil konstruktor kelas induk dan meneruskan Name
parameter dari konstruktor induk. Panggilan ini datang melalui : base()
metode dan dengan menambahkan dogName
yang diterima atau catName
parameter di dalam tanda kurung.
Catatan:
: base()
sintaks unik untuk konstruktor. Kita akan melihat cara lain untuk mengubah atau memperluas fungsionalitas kasus nanti.
.
Dengan pembaruan kode ini, sekarang kita dapat menjalankan program kita kembali dan melihat hasil yang mirip dengan Gambar 15.
Gambar 15:Hewan Berbicara, Menggunakan Warisan
Perhatikan bahwa kami tidak memiliki Sound
atau Name
properti yang didefinisikan dalam Dog
atau Cat
kelas. Kami juga tidak memiliki Speak()
metode. Sebaliknya, mereka tinggal di Animal
induknya kelas, dan Dog
dan Cat
kelas mewarisi properti dan metode ini.
Kami juga dapat membuat kelas lain sekarang, untuk semua jenis hewan dan kami hanya perlu mereplikasi pola Dog
dan Cat
kelas. Misalnya, kita mungkin membuat kelas-kelas ini:
class Parrot : Animal { public Parrot(string parrotName) : base(parrotName) { this.Sound = "I want a cracker!"; } } class Pig : Animal { public Pig(string pigName) : base(pigName) { this.Sound = "Oink"; } }
Kemudian, kita dapat membuat instance kelas-kelas ini di Program.cs:
Parrot myParrot = new Parrot("Polly"); myParrot.Speak(); Pig myPig = new Pig("Bacon"); myPig.Speak();
Sekarang kita akan memiliki kebun binatang yang sebenarnya di tangan kita ketika kita menjalankan program, seperti yang ditunjukkan pada Gambar 16.
Gambar 16:Kebun Binatang Empat Hewan Berbicara
Anda juga dapat membuat kelas sub-anak lebih lanjut dari kelas anak yang ada. Misalnya, Anda dapat memisahkan Dog
kelas menjadi Beagle
dan Pointer
atau memiliki Parrot
kelas mewarisi dari Bird
induknya kelas yang, pada gilirannya, mewarisi dari Animal
. Namun, membuat hierarki semacam ini berada di luar cakupan artikel ini, jadi mari kita lanjutkan dan akhirnya melihat bagaimana kita dapat mengganti, mengubah, atau memperluas fungsionalitas kelas induk di kelas turunan.
.
Memodifikasi Warisan
Kita dapat mengubah metode kelas induk dengan menggunakan teknik yang disebut mengganti . Sintaks untuk mengganti mungkin berbeda antar bahasa, tetapi prinsip mengubah metode induk di kelas anak tetap sama.
Di C#, kami menambahkan kata kunci override
diikuti dengan tanda tangan metode yang ingin Anda timpa. Kami juga harus mendeklarasikan di kelas induk bahwa kami mengizinkan anak-anak untuk mengganti metode dengan menambahkan virtual
kata kunci ke tanda tangan metode di kelas induk. (Bahasa lain mungkin tidak memerlukan indikasi tambahan ini.)
Dalam program kami, kami perlu memperbarui Speak()
metode di Animal
kelas.
public virtual void Speak() { Console.WriteLine(this.Name + " says " + this.Sound); }
Sekarang kita dapat menyisipkan penggantian Speak()
metode di Dog
kelas di awal blok kode kami untuk kelas ini.
class Dog : Animal { public override void Speak() { base.Speak(); Console.WriteLine("...and then runs around, chasing his tail"); } [remaining code omitted]
Kode ini memberitahu kita bahwa kita ingin menimpa apa yang terjadi pada metode induk Speak()
. Kami masih akan menjalankan metode induk menggunakan base.Speak()
panggil sebelum kami mengeluarkan saluran tambahan setelahnya.
Mengapa Anda ingin melakukannya? Yah, mungkin kita ingin anjing kita seantusias mungkin. Jalankan program dan lihat sendiri:
Gambar 17:Anjing Kami Mengganti Metode Kelasnya
Pertama, Snoopy menyalak seperti biasa:base.Speak()
metode memanggil Speak()
metode dari induk Animal
kelas. Kemudian sisa kode mengeluarkan baris kedua ke konsol. Secara efektif, kami memperluas kelas induk dengan menambahkan fungsionalitas baru ke kelas anak saja. Lihat bagaimana Cat
kelas tidak terpengaruh.
Tentu saja, kucing sangat sulit untuk melakukan apa yang Anda inginkan, jadi mari kita renungkan itu dalam kode. Perbarui Cat
kelas dan tambahkan override metode berikut, mirip dengan Dog
kelas.
class Cat : Animal { public override void Speak() { Console.WriteLine(Name + " doesn't speak but just sits there wondering when you will feed it."); } [remaining code omitted]
Tidak seperti yang kami lakukan di Dog
menimpa, kami tidak memanggil base.Speak()
metode kali ini. Tanpa panggilan itu, kita tidak akan pernah mengeksekusi Animal
Speak()
metode dan benar-benar mengubah apa yang terjadi dalam metode ini. Lihat sendiri:
Gambar 18:Kucing Kita Juga Mengganti Metode Kelasnya
Perhatikan juga bahwa karena kami telah membangun kembali kelas kami, kami tidak mengubah kode Program.cs. Perubahan ini menjadi contoh yang baik mengapa orientasi objek adalah teknik yang sangat kuat; kami telah sepenuhnya mengubah kode yang mendasarinya tanpa menyentuh program yang menggunakan kode itu. [Orientasi objek telah memungkinkan kami untuk mengisolasi banyak detail implementasi dan hanya mengekspos satu set kecil antarmuka yang perlu berinteraksi dengan program.]
Di Mana Kami Melanggar Aturan
Sebelum kita mengakhiri, saya ingin menunjukkan beberapa hal, terutama beberapa hal "buruk" yang telah kita lakukan.
Pertama, di kelas kita, kita memanggil Console.WriteLine()
metode secara langsung. Penggunaan ini bukanlah keputusan desain yang baik karena kelas harus independen dari bagaimana kita mengeluarkan hasil kelas.
Pendekatan yang lebih baik adalah mengembalikan data dari kelas sebagai gantinya dan kemudian mengeluarkannya sebagai bagian dari program. Kami kemudian akan mengizinkan program untuk memutuskan apa yang harus dilakukan dengan output daripada kelas, memungkinkan kami untuk menggunakan kelas yang sama di berbagai jenis program, apakah itu halaman web, Formulir Windows, QT, atau aplikasi Konsol.
Kedua, dalam contoh kita selanjutnya, semua properti adalah public
. Membuat properti ini publik melemahkan aspek keamanan orientasi objek, di mana kami berusaha melindungi data di kelas dari manipulasi dari luar. Namun, perlindungan properti dan metode dengan cepat menjadi kompleks ketika Anda berurusan dengan pewarisan, jadi saya ingin menghindari komplikasi itu, setidaknya pada tahap pengantar ini.
Akhirnya, tidak ada gunanya memiliki Sound
ditetapkan sebagai bagian dari konstruktor anak sama sekali karena kami juga menduplikasi kode itu. Akan menjadi desain yang lebih baik untuk membuat konstruktor di kelas induk yang menerima nama dan suara, dan kemudian menyebutnya sebagai bagian dari konstruktor anak. Namun, sekali lagi, demi kesederhanaan, saya tidak ingin memperkenalkan tanda tangan konstruktor yang berbeda pada tahap ini.
Jadi, sementara kami telah belajar banyak dalam tutorial bonus ini, Anda dapat melihat masih banyak lagi yang harus dipelajari. Namun, jangan terlalu khawatir tentang hal itu dulu. Anda dapat meluangkan waktu sejenak untuk mengucapkan selamat kepada diri sendiri karena telah mengikuti sepanjang jalan. Jika Anda telah mengikuti semua langkah, Anda telah mempelajari:
- Mengapa kami menggunakan orientasi objek
- Cara membuat kelas
- Cara membuat properti dan metode
- Cara membuat konstruktor dan apa yang mereka lakukan
- Cara memanfaatkan pewarisan dan mengapa itu menjadi fitur kuat dari orientasi objek
Saya harap Anda menikmati pelajaran tambahan ini dan tertarik untuk menjelajah lebih jauh. Pastikan untuk menghubungi kami kembali untuk konten baru di blog Atlantic.Net, dan pertimbangkan salah satu server hosting pribadi virtual kami yang terdepan di industri.
.