GNU/Linux >> Belajar Linux >  >> Linux

Cara :Pemrograman Berorientasi Objek – Konstruktor dan Warisan

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.
.


Linux
  1. Cara Mengelola dan Mendaftar Layanan di Linux

  2. Cara:Replikasi dan Konfigurasi DRBD

  3. Cara:Pemrograman Socket dengan Python

  1. Cara dual-boot Linux dan Windows

  2. Cara menginstal Elasticsearch dan Kibana di Linux

  3. Cara mempartisi dan memformat drive di Linux

  1. Apa itu chroot jail dan Bagaimana Cara Menggunakannya?

  2. Cara Memasang dan Menggunakan Helm di Kubernetes

  3. Bagaimana Cara Menginstal dan Menggunakan Layar Linux?