Özdeş imzalara sahip iki arayüz


13

Kartların iki önemli özelliğe sahip olduğu bir kart oyunu modellemeye çalışıyorum:

Birincisi bir etkidir. Bunlar, kartı oynadığınızda meydana gelen oyun durumundaki değişikliklerdir. Etki için arayüz aşağıdaki gibidir:

boolean isPlayable(Player p, GameState gs);
void play(Player p, GameState gs);

Ve ancak maliyetini karşılayabiliyorsanız ve tüm etkileri oynatılabiliyorsa kartın oynanabilir olduğunu düşünebilirsiniz. Şöyle ki:

// in Card class
boolean isPlayable(Player p, GameState gs) {
    if(p.resource < this.cost) return false;
    for(Effect e : this.effects) {
        if(!e.isPlayable(p,gs)) return false;
    }
    return true;
}

Tamam, şimdiye kadar oldukça basit.

Karttaki diğer özellikler ise yeteneklerdir. Bu yetenekler, istek üzerine etkinleştirebileceğiniz oyun durumundaki değişikliklerdir. Bunlar için arabirim ortaya çıktığında, etkinleştirilip etkinleştirilemeyeceklerini belirlemek için bir yönteme ve aktivasyonun uygulanması için bir yönteme ihtiyaç duyduklarını fark ettim. Sonuçta

boolean isActivatable(Player p, GameState gs);
void activate(Player p, GameState gs);

Ve bunu "oynamak" yerine "aktive" olarak adlandırmak dışında Abilityve Effectaynı imzanın olduğunu anlıyorum .


Aynı imzayla birden fazla arayüze sahip olmak kötü bir şey midir? Sadece bir tane kullanmalı mıyım ve aynı arabirimin iki setine sahip miyim? Bu şekilde:

Set<Effect> effects;
Set<Effect> abilities;

Eğer öyleyse, özdeş olmadıkları takdirde (daha fazla özellik yayınlandıkça), özellikle de ıraksaklarsa (yani her ikisinin de diğerinin almaması gereken bir şeyi kazanması durumunda, tek bir kazanım elde etmeleri gerekiyorsa , hangi yeniden düzenleme adımlarını izlemeliyim? diğeri ise tam bir alt küme)? Özellikle bir şeyler değiştiğinde onları birleştirmenin sürdürülebilir olmayacağından endişe duyuyorum.

İnce baskı:

Bu sorunun oyun geliştirmeyle ortaya çıktığını biliyorum, ancak özellikle oyun dışı geliştirmede, özellikle de birden fazla müşterinin iş modellerini hemen hemen tek bir uygulamada barındırmaya çalışırken, bu kadar kolay sürünebilecek bir sorun olduğunu hissediyorum. birden fazla iş etkisi ile yaptığım her proje ... Ayrıca, kullanılan parçacıklar Java parçacıklarıdır, ancak bu çok sayıda nesne yönelimli dilde de kolaylıkla uygulanabilir.


Sadece KISS ve YAGNI'yi takip edin ve iyi olmalısınız.
Bernard

2
Bu sorunun ortaya çıkmasının tek nedeni, inanılmaz derecede geniş ve kısıtlanmamış Player ve GameState parametreleri nedeniyle işlevlerinizin çok fazla duruma erişebilmesidir.
Lars Viklund

Yanıtlar:


18

İki arabirimin aynı sözleşmeye sahip olması, aynı arabirim oldukları anlamına gelmez.

Liskov İkame İlkesi şunları belirtir:

Q (x), T tipi x nesneleri hakkında kanıtlanabilir bir özellik olsun. S (S), S'nin T'nin bir alt türü olduğu S tipi y nesneleri için kanıtlanabilir olmalıdır.

Veya başka bir deyişle: Bir arayüz veya süper tip için doğru olan her şey tüm alt tipleri için doğru olmalıdır.

Açıklamanızı doğru anlıyorsam, bir yetenek bir etki değildir ve bir etki bir yetenek değildir. İkisinden biri sözleşmesini değiştirirse, diğerinin sözleşmeyi değiştirmesi pek olası değildir. Onları birbirine bağlamak için iyi bir neden göremiyorum.


2

Gönderen Wikipedia : " arayüz genellikle veri içermiyor soyut türünü tanımlamak için kullanılır, ancak İFŞA davranışları yöntemleri olarak tanımlanır ". Bence bir arayüz bir davranışı tanımlamak için kullanılır, bu yüzden farklı davranışlarınız varsa farklı arayüzlere sahip olmak mantıklıdır. Sorunuzu okuduğum izlenimi okumak, farklı davranışlar hakkında konuşmanızdır, bu nedenle farklı arayüzler en iyi yaklaşım olabilir.

Kendinizin söylediği bir başka nokta da bu davranışlardan birinin değişmesi. Peki sadece bir arayüzünüz olduğunda ne olur?


1

Kart oyununuzun kuralları "efektler" ve "yetenekler" arasında bir ayrım yaparsa, bunların farklı arayüzler olduğundan emin olmanız gerekir. Bu, yanlışlıkla birini diğerinin gerekli olduğu yerlerde kullanmanıza engel olacaktır.

Bununla birlikte, eğer çok benzer iseler, onları ortak bir atadan çıkarmak mantıklı olabilir. Dikkatlice düşünün: her zaman olacağını "etkileri" ve "yeteneklerini" inanmak için nedenlerimiz var mı mutlaka aynı arayüze sahip? effectArabirime bir öğe eklerseniz, arabirime aynı öğenin eklenmesini bekler misiniz ability?

Öyleyse, bu tür öğeleri featureher ikisinden de türetildikleri ortak bir arayüze yerleştirebilirsiniz. Değilse, onları birleştirmeye çalışmamalısınız - temel ve türetilmiş arayüzler arasında bir şeyler taşıyarak zamanınızı harcayacaksınız. Bununla birlikte, ortak taban arayüzünü "kendinizi tekrar etmeyin" dışında hiçbir şey için kullanmak istemediğiniz için, bu kadar fark yaratmayabilir. Ve eğer bu amaca sadık kalırsanız, sanırım başlangıçta yanlış seçim yaparsanız, daha sonra düzeltmek için yeniden düzenleme yapmak nispeten basit olabilir.


0

Gördüğünüz temel olarak tip sistemlerin sınırlı ifadesinin bir eseridir.

Teorik olarak, yazı sisteminiz bu iki arayüzün davranışını doğru bir şekilde belirlemenize izin verdiyse, davranışları farklı olduğu için imzaları farklı olacaktır. Pratik olarak, tip sistemlerin ifade edilebilirliği Durma Sorunu ve Pirinç Teoremi gibi temel sınırlamalarla sınırlıdır, bu nedenle davranışların her yönü ifade edilemez.

Şimdi, farklı tip sistemler farklı ifade derecelerine sahiptir, ancak her zaman ifade edilemeyen bir şey olacaktır .

Örneğin: farklı hata davranışına sahip iki arabirim C # 'da aynı imzayı taşıyabilir, ancak Java'da olmayabilir (çünkü Java istisnalarında imzanın bir parçasıdır). Davranışları yalnızca yan etkilerinde farklılık gösteren iki arabirim Java'da aynı imzayı taşıyabilir, ancak Haskell'de farklı imzalara sahip olacaktır.

Bu nedenle, farklı davranışlar için aynı imzayla sonuçlanmanız her zaman mümkündür. Bu iki davranışı sadece nominal bir seviyeden daha fazla ayırt edebilmenin önemli olduğunu düşünüyorsanız, daha fazla (veya farklı) ifade tipi bir sisteme geçmeniz gerekir.

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.