Apakah desain OOP yang buruk ini untuk simulasi yang melibatkan antarmuka?

13

Saya merancang program OOP kecil saya sendiri untuk mensimulasikan Vampir, Serigala, Manusia dan Truk dan saya mencoba menerapkan pemahaman saya sendiri yang terbatas tentang Antarmuka.

( Saya masih abstrak di sini dan belum mengimplementasikan kode, jadi ini pertanyaan desain OOP ... saya rasa!)

Apakah saya benar dalam mencari 'perilaku umum' antara kelas-kelas ini dan mengimplementasikannya sebagai antarmuka ?

Misalnya, Vampir dan Serigala menggigit ... jadi haruskah saya memiliki antarmuka gigitan?

public class Vampire : Villain, IBite, IMove, IAttack

Demikian juga untuk Truk ...

public class Truck : Vehicle, IMove

Dan untuk Manusia ...

public class Man : Human, IMove, IDead

Apakah pemikiran saya ada di sini? (Hargai bantuan Anda)

pengguna3396486
sumber
14
Hewan, sayuran dan mineral jarang menjadi contoh yang baik untuk implementasi aplikasi. Implementasi aktual umumnya lebih abstrak, seperti IEnumerable, IEquatable, dll
Robert Harvey
6
Anda memiliki satu penyebutan tunggal tentang apa yang akan dilakukan objek Anda di perangkat lunak Anda ("bite"). Perangkat lunak biasanya dirancang untuk melakukan sesuatu, mendasarkan model objek hanya pada karakteristik tidak memimpin di mana pun.
tofro
@tofro Niat saya adalah bahwa IBite akan berisi beberapa metode yang akan menerapkan perilaku mengenai (1) Pengurangan tingkat 'kehidupan / energi' orang lain (2) Tampilan atau doa grafik 'darah' dan (3) pembaruan statika simulasi data (seperti NoOfBites). Saya pikir saya bisa menghargai bahwa antarmuka paling baik digunakan untuk mengimplementasikan serangkaian perilaku metode.
user3396486
2
Bukankah kelas Manusia, Vampir, dan Kendaraan sudah mengimplementasikan antarmuka IMove? Mengapa Anda perlu membuat subclass mengimplementasikannya terlalu jelas?
Pierre Arlaud
Apakah semua antarmuka ini benar-benar diperlukan? Untungnya, dalam Python Anda tidak membutuhkan hal ini, eh yang merupakan perubahan yang sangat menyegarkan (bahasa pertama saya adalah Object Pascal). Metode virtual juga bisa menjadi solusi yang lebih baik dalam beberapa kasus.
Ajasja

Jawaban:

33

Secara umum Anda ingin memiliki antarmuka untuk karakteristik umum clasess Anda.

Saya setengah setuju dengan @Robert Harvey dalam komentar, yang mengatakan bahwa biasanya antarmuka mewakili fitur kelas yang lebih abstrak. Namun demikian, saya menemukan mulai dari contoh yang lebih konkret cara yang baik untuk mulai berpikir abstrak.

Sementara contoh Anda secara teknis benar (yaitu ya, baik vampir dan serigala menggigit, sehingga Anda dapat memiliki antarmuka untuk itu), ada pertanyaan tentang relevansi. Setiap objek memiliki ribuan karakteristik (mis. Hewan mungkin memiliki bulu, dapat berenang, dapat memanjat pohon, dan sebagainya). Apakah Anda akan membuat antarmuka untuk semuanya? Sangat kecil kemungkinannya.

Anda biasanya ingin antarmuka untuk hal-hal yang masuk akal untuk dikelompokkan dalam suatu aplikasi secara keseluruhan. Misalnya, jika Anda membuat game, Anda dapat memiliki larik objek IMove dan memperbarui posisinya. Jika Anda tidak ingin melakukan itu, memiliki antarmuka IMove sangat tidak berguna.

Intinya, jangan over engineer. Anda perlu berpikir tentang bagaimana Anda akan menggunakan antarmuka itu, dan 2 kelas yang memiliki metode yang sama bukanlah alasan yang cukup baik untuk membuat antarmuka.

Paul92
sumber
1
Saya tentu berharap setiap objek tidak memiliki ribuan atribut.
Gardenhead
4
Atribut tidak seperti dalam atribut oop tetapi atribut tata bahasa / karakteristik (hal-hal seperti enumerable, sebanding, dll): D. Pilihan kata yang salah.
Paul92
3
Perlu dicatat bahwa antarmuka yang bermanfaat adalah yang akan Anda gunakan. Misalnya, IBitetidak terlalu berguna, tetapi Anda mungkin ingin IAttackagar Anda dapat mengatasi semua hal yang membuat serangan, atau IUpdateagar Anda dapat menjalankan pembaruan untuk semuanya, atau IPhysicsEnabledagar Anda dapat menerapkan fisika pada mereka, dll.
anaximander
1
Jawaban ini menimbulkan beberapa poin yang sangat bagus. Paragraf akhir meringkasnya dengan cukup baik; setidaknya sebaik yang Anda bisa dengan tingkat detail yang disediakan.
Lightness Races dengan Monica
1
metode pengelompokan commons lebih cocok untuk kelas abstrak. Antarmuka dibuat untuk merancang kontrak yang harus menghormati mereka yang mengimplementasikannya, bukan mengelompokkan implementasi yang sama untuk beberapa objek.
Walfrat
28

Sepertinya Anda sedang membuat banyak antarmuka metode tunggal . Ini bagus di permukaannya tetapi perlu diingat bahwa antarmuka tidak dimiliki oleh kelas / es yang mengimplementasikannya. Mereka dimiliki oleh klien yang menggunakannya. Klien memutuskan apakah sesuatu perlu sesuatu yang bisa bergerak dan menyerang.

Jika saya memiliki Combatkelas dengan fight()metode, metode itu mungkin perlu memanggil keduanya move()dan attack()pada objek yang sama. Itu sangat menyarankan perlunya ICombatantantarmuka yang fight()dapat memanggil move()dan attack()melalui. Ini lebih bersih daripada fight()mengambil IAttackobjek dan melemparkannya IMoveuntuk melihat apakah benda itu juga bisa bergerak.

Itu tidak berarti Anda juga tidak dapat memiliki IMove IAttackantarmuka. Saya hanya berharap Anda tidak membuatnya tanpa klien membutuhkannya. Sebaliknya, jika tidak ada klien yang perlu membuat objek bergerak dan menyerang maka ICombatanttidak diperlukan.

Cara sederhana dalam memandang antarmuka sering kali hilang karena orang suka mengikuti contoh. Antarmuka pertama yang kami temukan adalah di perpustakaan. Sayangnya, perpustakaan tidak tahu apa itu klien mereka. Jadi mereka hanya bisa menebak kebutuhan klien mereka. Bukan contoh terbaik untuk diikuti.

candied_orange
sumber
1
Sialan ini bagus. Permainan sepertinya cara yang sangat baik untuk menggunakan dan menjelaskan OOP.
JeffO
6
@ Jeffe sampai Anda benar-benar mengimplementasikan permainan yang cukup besar dan menyadari bahwa OOP adalah kekacauan panas dan Anda akan lebih baik dengan sistem berbasis komponen atau desain yang berorientasi data.
Darkhogg
"Antarmuka dimiliki oleh klien yang menggunakannya"
Tibos
1
1 untuk perbedaan antara perpustakaan dan aplikasi, saya sering (terlalu banyak?: /) Membaca banyak hal yang hanya cocok untuk satu dan bukan yang lain.
Walfrat
3

Pertimbangkan apakah akan umum untuk memiliki koleksi objek dengan kombinasi kemampuan yang berbeda, dan apakah kode mungkin ingin melakukan tindakan terhadap item-item itu, dalam koleksi, yang mendukungnya . Jika demikian, dan jika ada "perilaku default" yang masuk akal untuk objek yang tidak memiliki dukungan yang berguna untuk beberapa tindakan, mungkin bermanfaat untuk memiliki antarmuka yang diimplementasikan oleh berbagai kelas, bukan hanya mereka yang dapat berperilaku bermanfaat.

Sebagai contoh, anggaplah hanya beberapa jenis makhluk yang dapat memiliki Woozles, dan seseorang ingin makhluk seperti itu memiliki NumerOfWoozlesproperti. Jika properti seperti itu berada di antarmuka yang hanya diterapkan oleh makhluk yang dapat memiliki Woozles, maka kode yang ingin menemukan jumlah total Woozles yang dipegang oleh kumpulan makhluk dari jenis campuran harus mengatakan sesuatu seperti:

int total = 0;
foreach (object it in creatures)
{
   IWoozleCountable w = trycast(it, IWoozleCountable);
   if (w != null) total += w.WoozleCount;
}

Namun, jika WoozleCount adalah anggota Creature / ICreature, meskipun beberapa subtipe akan mengesampingkan implementasi WoozleCount default Creature yang selalu mengembalikan nol, kode dapat disederhanakan menjadi:

int total = 0;
foreach (ICreature it in creatures)
   total += it.WoozleCount;

Sementara beberapa orang mungkin kecewa dengan gagasan bahwa setiap makhluk menerapkan properti WoozleCount yang benar-benar hanya berguna untuk beberapa subtipe, properti itu akan bermakna untuk semua jenis, apakah itu akan berguna atau tidak dengan item yang diketahui jenisnya, dan saya akan menganggap antarmuka "kitchen sink" kurang berbau kode daripada operator trycast.

supercat
sumber