Arabirimleri içeren bir simülasyon için bu kötü OOP tasarımı mı?


13

Vampirleri, Kurtları, İnsanları ve Kamyonları simüle etmek için kendi küçük OOP programımı tasarlıyorum ve kendi sınırlı arayüzler arayüzümü uygulamaya çalışıyorum.

( Ben hala burada soyutlama ve henüz kod uygulaması yok, bu yüzden OOP tasarımı bir soru ... sanırım!)

Bu sınıflar arasında 'ortak davranış' aramak ve bunları arayüz olarak uygulamakta haklı mıyım ?

Örneğin, Vampirler ve Kurtlar ısırır ... Öyleyse bir ısırık arayüzüm olmalı mı?

public class Vampire : Villain, IBite, IMove, IAttack

Aynı şekilde Kamyonlar için ...

public class Truck : Vehicle, IMove

Ve İnsanlar için ...

public class Man : Human, IMove, IDead

Düşüncem tam burada mı? (Yardımınıza minnettar olurum)


14
Hayvanlar, sebzeler ve mineraller nadiren uygulama uygulamaları için iyi örnekler verir. Gerçekleştirilen uygulamaların gibi genellikle daha soyut IEnumerable, IEquatablevb
Robert Harvey

6
Nesnelerinizin yazılımınızda ne yapmak üzere oldukları hakkında tek bir sözünüz var ("ısırık"). Yazılım normalde bir şey yapmak için tasarlanmıştır , bir nesne modelini sadece karakteristiklere dayandırmak hiçbir yere götürmez.
tofro

Niyetim, IBite'nin (1) Başka birinin 'yaşam / enerji' seviyesinin azaltılması (2) 'Kan' grafiklerinin ortaya çıkması veya çağrılması ve (3) simülasyon istatistiklerinin güncellenmesi ile ilgili davranışları uygulayacak birden fazla yöntem içermesi idi. veriler (NoOfBites gibi). Ben bir arayüz en iyi yöntem davranışları uygulamak için kullanılan olduğunu takdir düşünüyorum.
user3396486

2
İnsan, Vampir ve Araç sınıfları IMove arayüzünü zaten uygulamıyor mu? Neden alt sınıfların bunu çok açık bir şekilde uygulamasına ihtiyaç duyuyorsunuz?
Pierre Arlaud

Tüm bu arayüzler gerçekten gerekli mi? Python'da neyse ki, bunlardan hiçbirine ihtiyacınız yok, ehich gerçekten ferahlatıcı bir değişiklikti (ilk dilim Object Pascal'dı). Ayrıca sanal yöntemler bazı durumlarda daha iyi bir çözüm olabilir.
Ajasja

Yanıtlar:


33

Genel olarak, sınıfınızın ortak özellikleri için arayüzlere sahip olmak istersiniz.

Genellikle arayüzlerin sınıfların daha soyut özelliklerini temsil ettiğini söyleyen yorumlarda @Robert Harvey ile yarı-katılıyorum. Yine de, daha somut örneklerden başlayarak soyut düşünmeye başlamanın iyi bir yolunu buluyorum.

Örneğiniz teknik olarak doğru olsa da (yani evet, hem vampirler hem de kurtlar ısırır, böylece bunun için bir arayüze sahip olabilirsiniz), ilgili bir soru vardır. Her nesnenin binlerce özelliği vardır (örneğin hayvanlar kürklü olabilir, yüzebilir, ağaçlara tırmanabilir, vb.). Hepsi için bir arayüz oluşturacak mısınız? Çok daha az muhtemel.

Genellikle bir uygulamada bir bütün olarak gruplandırmanın anlamlı olduğu şeyler için arayüzler istersiniz. Örneğin, bir oyun oluşturuyorsanız, bir dizi IMove nesnesine sahip olabilir ve konumlarını güncelleyebilirsiniz. Bunu yapmak istemiyorsanız, IMove arayüzüne sahip olmak oldukça işe yaramaz.

Mesele şu ki, aşırı mühendislik yapmayın. Bu arayüzü nasıl kullanacağınızı düşünmeniz gerekiyor ve ortak bir yönteme sahip 2 sınıf, bir arayüz oluşturmak için yeterince iyi bir neden değil.


1
Kesinlikle her nesnenin umut değil niteliklerin binlerce sahiptir.
gardenhead

4
Özniteliklerde değil, dilbilgisi özniteliklerinde / özelliklerinde (numaralandırılabilir, karşılaştırılabilir vb. Gibi) öznitelikler: D. Kelimelerin kötü seçimi.
Paul92

3
Yararlı olan arayüzlerin kullanacağınız özellikler olduğunu belirtmek gerekir. Örneğin, IBiteözellikle yararlı değildir, ancak IAttacksaldırı yapan tüm şeyleri üzerinde çalışabilmenizi veya IUpdateher şeyin güncellemelerini çalıştırabilmenizi veya IPhysicsEnabledböylece onlara fizik uygulayabilmenizi vb.
İsteyebilirsiniz

1
Bu cevap bazı iyi noktaları ortaya çıkarıyor. Son paragraf oldukça iyi özetliyor; en az yanı sıra sağlanan ayrıntı düzeyi ile yapabilirsiniz.
Yörüngedeki Hafiflik Yarışları

1
gruplama yöntemleri soyut sınıflar için daha uygun. Arayüz, bazı nesneler için aynı uygulamayı gruplandırmak yerine, onu uygulayanlara saygı duyması gereken sözleşmeler tasarlamak için yapılır.
Walfrat

29

Görünüşe göre bir grup tekli yöntem arayüzü oluşturuyorsunuz . Bu yüzünde bir sorun yok ama arayüzlerin onları uygulayan sınıflara ait olmadığını unutmayın. Onları kullanan müşterilere aittirler. Müşteriler, bir şeyin hareket edebilecek ve saldırabilecek bir şey olması gerekip gerekmediğine karar verir.

Bir varsa Combatbir ile sınıf fight()yöntemiyle, bu yöntem büyük olasılıkla hem çağırmak için bir ihtiyaç vardır move()ve attack()aynı nesne üzerinde. Bu , arayabilen ve arayabilen bir ICombatantarayüze ihtiyaç olduğunu şiddetle göstermektedir . Bu, bir nesneyi alıp hareket edip edemeyeceğini görmek için onu dökmekten daha temizdir .fight()move()attack()fight()IAttackIMove

Bu, IMove IAttackarayüzlere sahip olamayacağınız anlamına gelmez . Umarım bir müşteriye ihtiyaç duymadan onları yapmazsınız. Tersine, hiçbir müşterinin bir nesneyi hem hareket ettirmesi hem de saldırması yapması ICombatantgerekmiyorsa, buna gerek yoktur.

Arayüzlere bakmanın bu basit yolu genellikle kaybolur çünkü insanlar aşağıdaki örnekleri severler. Karşılaştığımız ilk arayüzler kütüphanelerdedir. Maalesef kütüphanelerin müşterileri hakkında hiçbir fikri yoktur. Böylece sadece müşterilerinin ihtiyaçlarını tahmin edebilirler. Takip edilecek en iyi örnek değil.


1
Kahretsin bu iyi. Oyun, OOP'yi kullanmak ve açıklamak için gerçekten iyi bir yol gibi görünüyor.
JeffO

7
@JeffO, aslında oldukça büyük bir oyun gerçekleştirene ve OOP'un sıcak bir karmaşa olduğunu anlayana ve bileşen tabanlı sistemler veya veri odaklı tasarımlarla daha iyi olacağınızı anlayana kadar.
Darkhogg

"Arayüzler onları kullanan istemcilere aittir"
Tibos


1
Kütüphaneler ve uygulama arasındaki fark için +1, sık sık (çok fazla?: /) Biri için uygun olan, diğeri için uygun olmayan tonlarca şey okurum.
Walfrat

3

Farklı yetenek kombinasyonlarına sahip nesne koleksiyonlarına sahip olmanın yaygın olup olmayacağını ve kodun bir koleksiyon içinde onu destekleyen bu öğeler üzerinde bir eylem gerçekleştirmek isteyip istemediğini düşünün . Öyleyse ve bazı eylemler için yararlı desteği olmayan nesneler için mantıklı bir "varsayılan davranış" olacaksa, yalnızca kullanışlı bir şekilde davranabilenlerin değil, çok çeşitli sınıflar tarafından arabirimlerin uygulanması yararlı olabilir.

Örneğin, sadece birkaç tür yaratığın Woozles'e sahip olabileceğini ve bu tür yaratıkların bir NumerOfWoozlesmülke sahip olmasını istediğini varsayalım . Böyle bir mülk, sadece Woozles'a sahip olabilen yaratıklar tarafından uygulanan bir arayüzdeyse, karışık tür yaratıklardan oluşan bir koleksiyon tarafından tutulan toplam Woozles sayısını bulmak isteyen kodun şöyle bir şey söylemesi gerekir:

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

Bununla birlikte, WoozleCount bir Creature / ICreature üyesiyse, birkaç alt tür Creature'ın her zaman sıfır döndüren varsayılan WoozleCount uygulamasını geçersiz kılacak olsa da, kod basitleştirilebilir:

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

Bazı insanlar, her Creature'ın yalnızca birkaç alt tür için gerçekten yararlı olan bir WoozleCount özelliği uygulamasına dikkat çekerken , bu türler olduğu bilinen öğelerle yararlı olsa da olmasa da , bu özellik tüm türler için anlamlı olacaktır, ve "mutfak lavabo" arayüzü trycast operatörü daha az bir kod kokusu olarak kabul ediyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.