Bagaimana polimorfisme digunakan di dunia nyata? [Tutup]

17

Saya mencoba memahami bagaimana Polimorfisme digunakan dalam proyek kehidupan nyata, tetapi saya hanya dapat menemukan contoh klasik (atau sesuatu yang serupa dengan itu) memiliki Animalkelas induk dengan metode speak(), dan banyak kelas anak yang menimpa metode ini, dan sekarang Anda dapat memanggil metode speak()pada salah satu objek anak, misalnya:

Animal animal;

animal = dog;
animal.speak();

animal = cat;
animal.speak();
Christopher
sumber
1
Koleksi, yang Anda lihat dan gunakan dalam setiap hari, itu sendiri sudah cukup untuk memahami apa itu polimorfisme. Tetapi bagaimana menggunakan polimorfisme secara efektif dalam pemecahan masalah adalah keterampilan yang Anda peroleh paling banyak melalui pengalaman dan bukan hanya dengan berdiskusi. Pergi dan jadikan tangan Anda kotor.
Durgadass S
Jika Anda memiliki serangkaian jenis yang semuanya akan mendukung beberapa jenis antarmuka minimum (misalnya, serangkaian objek yang perlu digambar), antarmuka biasanya cocok untuk menyembunyikan perbedaan antara objek dari panggilan untuk menggambarnya. Juga jika Anda membuat (atau bekerja dengan) API yang memiliki metode yang dapat melayani objek dasar dan sejumlah besar jenis yang mewarisi kurang lebih dengan cara yang sama , polimorfisme mungkin merupakan cara terbaik untuk abstrak perbedaan antara tipe-tipe itu.
jrh
Secara umum jika Anda sering membuat metode kelebihan beban untuk menangani berbagai jenis dan kodenya mirip, atau jika Anda if(x is SomeType) DoSomething()sering menulis , mungkin ada baiknya menggunakan polimorfisme. Bagi saya polimorfisme adalah keputusan yang mirip dengan kapan membuat metode terpisah, jika saya menemukan bahwa saya mengulangi kode beberapa kali, saya biasanya mengubahnya menjadi sebuah metode, dan jika saya if object is this type do thissering membuat kode, saya mungkin membuat kode. layak refactoring dan menambahkan antarmuka atau kelas.
jrh

Jawaban:

35

Stream adalah contoh polimorfisme yang bagus.

Stream mewakili "urutan byte yang bisa dibaca atau ditulis". Tetapi urutan ini dapat berasal dari file, memori, atau banyak jenis koneksi jaringan. Atau dapat berfungsi sebagai dekorator, yang membungkus aliran yang ada dan mengubah byte dalam beberapa cara, seperti enkripsi atau kompresi.

Dengan cara ini, klien yang menggunakan Stream tidak perlu peduli dari mana asalnya. Hanya saja mereka bisa dibaca secara berurutan.

Beberapa orang akan mengatakan Streamini adalah contoh polimorfisme yang salah, karena ia mendefinisikan banyak "fitur" yang tidak didukung oleh implementornya, seperti aliran jaringan yang hanya memungkinkan membaca atau menulis, tetapi tidak keduanya sekaligus. Atau kurang mencari. Tapi itu hanya masalah kompleksitas, karena Streamdapat dibagi lagi menjadi banyak bagian yang dapat diimplementasikan secara mandiri.

Euforia
sumber
2
Dalam bahasa dengan multiple dan virtual inheritance seperti C ++, contoh ini bahkan dapat menunjukkan pola "berlian yang ditakuti" ... dengan menurunkan kelas input dan output stream dari kelas stream dasar, dan memperluas keduanya untuk membuat aliran I / O
gyre
2
@gy dan dilakukan dengan baik, tidak ada alasan untuk "takut" pola berlian. Perlu menyadari lawan yang berlawanan dalam berlian dan tidak menyebabkan konflik nama dengan itu penting, dan tantangan, dan menjengkelkan, dan alasan untuk menghindari pola berlian di mana bisa dilakukan ... tetapi jangan terlalu takut ketika hanya memiliki, katakanlah, konvensi penamaan dapat memecahkan masalah.
KRyan
+1 Streamadalah contoh polimorfisme favorit saya sepanjang masa. Saya bahkan tidak berusaha untuk mengajar orang-orang model 'binatang, mamalia, anjing' yang cacat lagi, Streamtetapi melakukan pekerjaan yang lebih baik.
Pharap
@Ryan Saya tidak mengungkapkan pikiran saya sendiri dengan menyebutnya "berlian yang ditakuti," Saya baru saja mendengarnya disebut demikian. Saya sangat setuju; Saya pikir itu adalah sesuatu yang setiap pengembang harus dapat membungkus kepala mereka dan menggunakannya dengan tepat.
Pilin
@gy Oh, ya, saya benar-benar mengerti; itu sebabnya saya mulai dengan "dan," untuk menunjukkan bahwa itu adalah perpanjangan dari pemikiran Anda, bukan sebuah kontradiksi.
KRyan
7

Contoh permainan yang terkait biasanya akan menjadi kelas dasar Entity, menyediakan anggota umum seperti draw()atauupdate() .

Untuk contoh berorientasi data yang lebih murni mungkin ada kelas dasar yang Serializablemenyediakan umum saveToStream()dan loadFromStream().

Mario
sumber
6

Ada berbagai jenis polimorfisme, yang menarik biasanya polimorfisme runtime / pengiriman dinamis.

Deskripsi polimorfisme runtime tingkat sangat tinggi adalah bahwa pemanggilan metode melakukan hal-hal yang berbeda tergantung pada tipe runtime argumennya: objek itu sendiri bertanggung jawab untuk menyelesaikan pemanggilan metode. Ini memungkinkan fleksibilitas yang sangat besar.

Salah satu cara paling umum untuk menggunakan fleksibilitas ini adalah untuk injeksi dependensi , misalnya agar saya dapat beralih di antara implementasi yang berbeda atau untuk menyuntikkan objek tiruan untuk pengujian. Jika saya tahu sebelumnya bahwa hanya akan ada sejumlah pilihan yang mungkin saya dapat mencoba untuk melakukan hardcode dengan kondisional, misalnya:

void foo() {
  if (isTesting) {
    ... // do mock stuff
  } else {
    ... // do normal stuff
  }
}

Ini membuat kode sulit untuk diikuti. Alternatifnya adalah dengan memperkenalkan antarmuka untuk operasi tersebut dan menulis implementasi normal dan implementasi tiruan dari antarmuka itu, dan "menyuntikkan" ke implementasi yang diinginkan pada saat runtime. "Injeksi ketergantungan" adalah istilah yang rumit untuk "melewatkan objek yang benar sebagai argumen".

Sebagai contoh dunia nyata, saya saat ini sedang mengerjakan masalah pembelajaran mesin. Saya memiliki algoritma yang memerlukan model prediksi. Tapi saya ingin mencoba algoritma pembelajaran mesin yang berbeda. Jadi saya mendefinisikan sebuah antarmuka. Apa yang saya butuhkan dari model prediksi saya? Diberikan beberapa sampel input, prediksi dan kesalahannya:

interface Model {
  def predict(sample) -> (prediction: float, std: float);
}

Algoritme saya mengambil fungsi pabrik yang melatih model:

def my_algorithm(..., train_model: (observations) -> Model, ...) {
  ...
  Model model = train_model(observations);
  ...
  y, std = model.predict(x)
  ...
}

Saya sekarang memiliki berbagai implementasi dari antarmuka model dan dapat membandingkannya satu sama lain. Salah satu implementasi ini sebenarnya mengambil dua model lain dan menggabungkannya menjadi model yang dikuatkan. Jadi berkat antarmuka ini:

  • algoritma saya tidak perlu tahu tentang model spesifik sebelumnya,
  • Saya dapat dengan mudah menukar model, dan
  • Saya memiliki banyak fleksibilitas dalam mengimplementasikan model saya.

Kasus penggunaan klasik polimorfisme ada di GUI. Dalam kerangka kerja GUI seperti Java AWT / Swing / ... ada komponen yang berbeda . Antarmuka komponen / kelas dasar menjelaskan tindakan seperti mengecat dirinya sendiri ke layar, atau bereaksi terhadap klik mouse. Banyak komponen yang merupakan wadah yang mengelola sub-komponen. Bagaimana wadah seperti itu menarik dirinya sendiri?

void paint(Graphics g) {
  super.paint(g);
  for (Component child : this.subComponents)
    child.paint(g);
}

Di sini, wadah tidak perlu tahu tentang jenis subkomponen yang tepat di muka - selama mereka sesuai dengan Componentantarmuka wadah hanya dapat memanggil paint()metode polimorfik . Ini memberi saya kebebasan untuk memperpanjang hirarki kelas AWT dengan komponen baru yang sewenang-wenang.

Ada banyak masalah berulang sepanjang pengembangan perangkat lunak yang dapat diselesaikan dengan menerapkan polimorfisme sebagai teknik. Pasangan solusi-masalah yang berulang ini disebut pola desain , dan beberapa di antaranya dikumpulkan dalam buku dengan nama yang sama. Dalam istilah buku itu, model pembelajaran mesin injeksi saya akan menjadi strategi yang saya gunakan untuk "mendefinisikan keluarga algoritma, merangkum masing-masing, dan membuatnya saling dipertukarkan". Contoh Java-AWT di mana komponen dapat berisi sub-komponen adalah contoh komposit .

Tetapi tidak setiap desain perlu menggunakan polimorfisme (di luar memungkinkan injeksi ketergantungan untuk pengujian unit, yang merupakan kasus penggunaan yang sangat baik). Sebagian besar masalah dinyatakan sangat statis. Akibatnya, kelas dan metode sering tidak digunakan untuk polimorfisme, tetapi hanya sebagai ruang nama yang nyaman dan untuk metode panggilan sintaksis cantik. Misalnya banyak pengembang lebih suka pemanggilan metode seperti account.getBalance()pada pemanggilan fungsi yang sebagian besar setara Account_getBalance(account). Itu pendekatan yang sangat bagus, hanya saja banyak "metode" panggilan tidak ada hubungannya dengan polimorfisme.

amon
sumber
6

Anda melihat banyak pewarisan dan polimorfisme di sebagian besar toolkit UI.

Misalnya, dalam toolkit JavaFX UI, Buttonmewarisi dari ButtonBasemana mewarisi dari Labeledmana mewarisi dari Controlmana mewarisi dari Regionmana mewarisi dari Parentmana mewarisi dari NodemanaObject . Banyak layer menimpa beberapa metode dari yang sebelumnya.

Ketika Anda ingin tombol itu muncul di layar, maka Anda menambahkannya ke Pane, yang dapat menerima apa pun yang diturunkan dariNode kecil. Tapi bagaimana sebuah Pane tahu apa yang harus dilakukan dengan Button ketika itu hanya melihatnya sebagai objek Node generik? Objek itu bisa berupa apa saja. Panel dapat melakukan itu karena Tombol mendefinisikan kembali metode Node dengan logika spesifik tombol apa pun. Panel hanya memanggil metode yang didefinisikan dalam Node dan meninggalkan sisanya ke objek itu sendiri. Ini adalah contoh sempurna polimorfisme terapan.

Toolkit UI memiliki signifikansi dunia nyata yang sangat tinggi, menjadikannya berguna untuk mengajar karena alasan akademis dan praktis.

Namun, toolkit UI juga memiliki kelemahan signifikan: Mereka cenderung besar . Ketika seorang insinyur perangkat lunak orang baru mencoba memahami cara kerja internal kerangka UI umum, mereka akan sering menghadapi lebih dari seratus kelas , kebanyakan dari mereka melayani tujuan yang sangat esoteris. "Apa-apaan ini ReadOnlyJavaBeanLongPropertyBuilder? Apakah ini penting? Apakah aku harus mengerti apa gunanya?" Pemula dapat dengan mudah tersesat di lubang kelinci itu. Jadi mereka mungkin melarikan diri dalam ketakutan atau tetap di permukaan di mana mereka hanya mempelajari sintaks dan berusaha untuk tidak berpikir terlalu keras tentang apa yang sebenarnya terjadi di bawah tenda.

Philipp
sumber
3

Meskipun sudah ada contoh bagus di sini, yang lain adalah mengganti hewan dengan perangkat:

  • Devicebisa powerOn(), powerOff(), setSleep()dan kaleng getSerialNumber().
  • SensorDevicedapat melakukan semua ini, dan menyediakan fungsi polimorfik seperti getMeasuredDimension(), getMeasure(), alertAt(threashhold)dan autoTest().
  • tentu saja, getMeasure()tidak akan diterapkan dengan cara yang sama untuk sensor suhu, detektor cahaya, detektor suara atau sensor volumetrik. Dan tentu saja, masing-masing sensor yang lebih khusus ini mungkin memiliki beberapa fungsi tambahan yang tersedia.
Christophe
sumber
2

Presentasi adalah aplikasi yang sangat umum, mungkin yang paling umum adalah ToString (). Yang pada dasarnya adalah Animal.Speak (): Anda memberi tahu objek untuk memanifestasikan dirinya.

Secara umum, Anda memberi tahu objek untuk "melakukan hal itu". Pikirkan Simpan, Muat, Inisialisasi, Buang, ProcessData, GetStatus.

Martin Maat
sumber
2

Penggunaan praktis pertama saya tentang polimorfisme adalah implementasi dari Heap di java.

Saya memiliki kelas dasar dengan penerapan metode insert, removeTop di mana perbedaan antara max dan min Heap hanya bagaimana metode membandingkan bekerja.

abstract class Heap {  

 abstract boolean compare ( int x , int y );

 boolean insert(int x ) { ... }

 int removeTop() { ... }
}

Jadi ketika saya ingin memiliki MaxHeap dan MinHeap saya bisa menggunakan warisan.

class MaxHeap extends Heap {

   MaxHeap(int maxSize) {super(maxSize);}

   @Override
   boolean compare(int x, int y) {
       return x>y; // x<y for minHeap
   }
}
Bazil
sumber
1

Berikut ini adalah skenario kehidupan nyata untuk polimorfisme tabel aplikasi / database web :

Saya menggunakan Ruby on Rails untuk mengembangkan aplikasi web, dan satu hal yang banyak dimiliki proyek saya adalah kemampuan untuk mengunggah file (foto, PDF, dll.). Jadi misalnya, Usermungkin memiliki beberapa gambar profil, dan Productmungkin juga memiliki banyak gambar produk. Keduanya memiliki perilaku mengunggah dan menyimpan gambar, serta mengubah ukuran, membuat thumbnail, dll. Agar tetap KERING dan berbagi perilaku Picture, kami ingin membuat Picturepolimorfik sehingga dapat menjadi milik keduanya Userdan Product.

Di Rails saya akan mendesain model saya sebagai berikut:

class Picture < ApplicationRecord
  belongs_to :imageable, polymorphic: true
end

class User < ApplicationRecord
  has_many :pictures, as: :imageable
end

class Product < ApplicationRecord
  has_many :pictures, as: :imageable
end

dan migrasi basis data untuk membuat picturestabel:

class CreatePictures < ActiveRecord::Migration[5.0]
  def change
    create_table :pictures do |t|
      t.string  :name
      t.integer :imageable_id
      t.string  :imageable_type
      t.timestamps
    end

    add_index :pictures, [:imageable_type, :imageable_id]
  end
end

Kolom imageable_iddan imageable_typedigunakan oleh Rails secara internal. Pada dasarnya, imageable_typememegang nama kelas ( "User", "Product", dll), dan imageable_idmerupakan id dari catatan terkait. Jadi imageable_type = "User"dan imageable_id = 1akan menjadi catatan di userstabel dengan id = 1.

Ini memungkinkan kami melakukan hal-hal seperti user.picturesmengakses gambar pengguna, serta product.picturesmendapatkan gambar produk. Kemudian, semua perilaku yang berhubungan dengan gambar dienkapsulasi di dalam Photokelas (dan bukan kelas yang terpisah untuk setiap model yang membutuhkan foto), sehingga semuanya tetap KERING.

Lebih banyak bacaan: Asosiasi rel polimorfik .

Chris Cirefice
sumber
0

Ada banyak algoritma penyortiran yang tersedia seperti bubble sort, sorting sort, quick sort, heap sort dll. Dan mereka memiliki kompleksitas yang berbeda dan mana yang optimal untuk digunakan tergantung pada berbagai faktor (mis: ukuran array)

Klien disediakan dengan antarmuka pengurutan hanya tentang menyediakan array sebagai input dan kemudian menerima array yang diurutkan. Selama runtime tergantung pada faktor-faktor tertentu implementasi penyortiran yang tepat dapat digunakan. Ini adalah salah satu contoh dunia nyata di mana polimorfisme digunakan.

Apa yang saya jelaskan di atas adalah contoh dari polimorfisme runtime sedangkan metode overloading adalah contoh waktu kompilasi polimorfis di mana kompiler tergantung pada tipe parameter i / p dan o / p dan jumlah parameter yang mengikat pemanggil dengan metode yang tepat pada waktu yang tepat itu sendiri.

Semoga ini bisa menjelaskan.

rahulaga_dev
sumber