Şablon yöntemini stratejiyle birleştirme


14

Yazılım mühendisliği dersimdeki bir görev, belirli bir oyunun farklı formlarını oynayabilen bir uygulama tasarlamaktır. Söz konusu oyun Mancala, bu oyunlardan bazılarına Wari veya Kalah deniyor. Bu oyunlar bazı yönlerden farklıdır, ancak sorum için oyunların aşağıdakilerde farklı olabileceğini bilmek önemlidir:

  • Bir hareketin sonucunun ele alınış şekli
  • Oyunun sonunun belirlenme şekli
  • Kazananın tespit edilme şekli

Bunu tasarlamak için aklıma gelen ilk şey strateji modelini kullanmaktı, algoritmalarda (oyunun gerçek kuralları) bir varyasyonum var. Tasarım şöyle görünebilir: resim açıklamasını buraya girin

Daha sonra kendi kendime Mancala ve Wari oyununda kazananın belirlenme şeklinin tamamen aynı olduğunu ve kodun çoğaltılacağını düşündüm. Bunun tanımı gereği, Mancala için kurallarda değişiklik olarak görülen 'bir kural, bir yer' veya KURU ilkesinin ihlali olduğunu düşünmüyorum, kuralın Wari'de de otomatik olarak değiştirilmesi gerektiği anlamına gelmez. Yine de profesörümden aldığım geri bildirimlerden farklı bir tasarım bulma izlenimi edindim.

Sonra bununla geldim: resim açıklamasını buraya girin

Her oyun (Mancala, Wari, Kalah, ...) sadece her kuralın arayüzünün türüne sahip olacaktı, yani WinnerDeterminerMancala 1.0 ile aynı olan bir Mancala 2.0 sürümü varsa, kazananın nasıl belirleneceği dışında Mancala versiyonlarını kullanır.

Bu kuralların bir strateji modeli olarak uygulanmasının kesinlikle geçerli olduğunu düşünüyorum. Ama asıl sorun, onu daha fazla tasarlamak istediğimde ortaya çıkıyor.

Şablon yöntem kalıbı hakkında okurken hemen bu soruna uygulanabileceğini düşündüm. Kullanıcı bir hamle yaptığında yapılan işlemler her zaman aynıdır ve aynı sıradadır:

  • deliklere taş yatırın (bu tüm oyunlar için aynıdır, bu yüzden şablon yönteminin kendisinde uygulanır)
  • hareketin sonucunu belirle
  • oyunun bir önceki hamle yüzünden bitip bitmediğini belirle
  • oyun bitmişse, kimin kazandığını belirleyin

Bu son üç adım yukarıda açıklanan strateji modelimde. Bu ikisini birleştirirken çok sorun yaşıyorum. Bulduğum olası bir çözüm, strateji modelini terk etmek ve aşağıdakileri yapmak olacaktır: resim açıklamasını buraya girin

Strateji örüntüsü ile bu tasarım arasındaki tasarım farkını gerçekten görmüyorum? Ama bir şablon yöntemi kullanmam gerektiğinden eminim (bir strateji kalıbı kullanmak zorunda olduğumdan emin olmama rağmen).

TurnTemplateNesneyi oluşturmaktan kimin sorumlu olacağını da belirleyemem , oysa strateji modeli ile soyut bir fabrika modeli kullanarak kolayca oluşturabileceğim nesne ailelerine (üç kural) sahip olduğumu hissediyorum. Daha sonra bir MancalaRuleFactory, WariRuleFactoryvb. Olurdu ve kuralların doğru örneklerini oluşturacaklar ve bana bir RuleSetnesneyi geri vereceklerdi .

Strateji + soyut fabrika modelini kullandığımı ve RuleSetiçindeki üç kural için algoritmalara sahip bir nesnem olduğunu varsayalım . Şablon yöntem desenini hala bununla kullanabileceğimi hissetmenin tek yolu bu RuleSetnesneyi benim iletmektir TurnTemplate. O zaman yüzeye çıkan 'sorun', somut uygulamalara asla ihtiyacım olmayacak TurnTemplate, bu sınıfların modası geçecek. Korunan yöntemlerde TurnTemplatesadece arayabiliyordum ruleSet.determineWinner(). Sonuç olarak, TurnTemplatesınıf artık soyut olmayacak, ancak somut hale gelmek zorunda kalacaktı, o zaman hala bir şablon yöntemi kalıbı mı?

Özetlemek gerekirse doğru şekilde mi düşünüyorum yoksa kolay bir şey mi kaçırıyorum? Doğru yoldaysanız, bir strateji kalıbını ve bir şablon yöntemi kalıbını nasıl birleştirebilirim?


1
Düşünmenizin hemen hemen yerinde olduğunu söyleyebilirim. Profesörünüzden aldığınız geri bildirim bunu doğrulamazsa, ondan kusurları işaret etmesini isteyin veya cevabın ardında ne olduğuna dair bir ipucu verin. Zihin okumaya çalışmayı bırak. Profesörünüzün (ve daha sonra kullanıcılarınızın) ne istediğiyle ilgili bir şey varsayalım, yapabileceğiniz en kötü şey olabilir.
Marjan Venema

... Mancala ve Wari oyununda kazananın tespit edilme şekli tamamen aynı ve kod tekrarlanacak. ” Bu, kodun neden kopyalandığını ima ediyor? Her iki sınıfın da aynı işlevi çağırmasına izin verin.
D Drmmr

Yanıtlar:


6

Tasarımlarınıza baktıktan sonra, hem birinci hem de üçüncü iterasyonlarınız daha zarif tasarımlar gibi görünüyor. Ancak, siz bir öğrenci olduğunuzu ve profesörünüzün size geri bildirimde bulunduğunu belirtiyorsunuz. Ödevinizin veya sınıfın amacının tam olarak ne olduğunu veya profesörünüzün önerdiği hakkında daha fazla bilgi bilmeden, aşağıda söylediğim her şeyi bir tuz tanesi ile alacağım.

İlk tasarımınızda, RuleInterfaceher oyuncunun sırasını nasıl ele alacağınızı, oyunun bitip bitmediğini nasıl belirleyeceğinizi ve oyun bittikten sonra kazananı nasıl belirleyeceğinizi tanımlayan bir arayüz olduğunu beyan edersiniz . Bu, varyasyon yaşayan bir oyun ailesi için geçerli bir arayüz gibi görünüyor. Ancak, oyunlara bağlı olarak çoğaltılmış kodunuz olabilir. Bir oyunun kurallarını değiştirme esnekliğinin iyi bir şey olduğunu kabul ediyorum, ancak kod çoğaltmanın kusurlar için korkunç olduğunu da iddia ediyorum. Hatalı kodu uygulamalar arasında kopyalarsanız / yapıştırırsanız ve birinde hata varsa, artık farklı konumlarda düzeltilmesi gereken birden çok hatanız var. Uygulamaları farklı zamanlarda yeniden yazarsanız, farklı konumlarda hatalar ortaya koyabilirsiniz. Bunların hiçbiri arzu edilmez.

İkinci tasarımınız derin bir miras ağacıyla oldukça karmaşık görünüyor. En azından bu tür bir sorunu çözmek için beklediğimden daha derin. Ayrıca uygulama ayrıntılarını diğer sınıflara ayırmaya başlıyorsunuz. Nihayetinde, bir oyunu modelliyor ve uyguluyorsunuz. Bahsettiğiniz şartlarda gözükmeyen bir hamle, oyunun sonu ve bir kazananın sonuçlarını belirlemek için kurallarınızı karıştırıp eşleştirmeniz gerekiyorsa, bu ilginç bir yaklaşım olabilir. . Oyunlarınız iyi tanımlanmış kurallar kümesidir ve oyunları olabildiğince ayrı varlıklara dahil etmeye çalışacağım.

Üçüncü tasarımınız en sevdiğim tasarım. Tek endişem doğru soyutlama düzeyinde olmaması. Şu anda, bir dönüşü modelliyorsunuz. Oyunu tasarlamayı tavsiye ederim. Taş kullanarak bir tür tahta üzerinde hamle yapan oyuncularınız olduğunu düşünün. Oyununuz bu aktörlerin hazır bulunmasını gerektiriyor. Buradan, algoritma değil doTurn()ama playGame()o sonlandırır sonra nihai hamlesine ilk hareket, gider, hangi. Her oyuncunun hamlesinden sonra oyunun durumunu ayarlar, oyunun nihai durumda olup olmadığını ve kazanırsa kazananı belirler.

Birinci ve üçüncü tasarımlarınıza daha yakından bakmanızı ve onlarla çalışmanızı tavsiye ederim. Prototipler açısından düşünmek de yardımcı olabilir. Bu arayüzleri kullanan istemciler neye benzer? Bir tasarım yaklaşımı, aslında bir oyunu başlatan ve oyunu oynayacak bir müşteriyi uygulamak için daha anlamlı mı? Ne ile etkileşime girdiğinin farkında olmalısınız. Özel durumunuzda, bu Gamesınıf ve diğer ilişkili öğeler - tek başına tasarlayamazsınız.


Bir öğrenci olduğunuzdan bahsettiğiniz için, bir yazılım tasarımı kursu için TA olduğum bir zamandan birkaç şey paylaşmak istiyorum:

  • Desenler sadece geçmişte işe yarayan şeyleri yakalamanın bir yoludur, ancak onları diğer tasarımlarda kullanılabilecek bir noktaya soyutlar. Her tasarım deseni kataloğu, bir desene bir ad verir, niyetlerini ve nerede kullanılabileceğini ve sonuçta tasarımınızı kısıtlayacağı durumları açıklar.
  • Tasarım deneyim ile gelir. Tasarımda iyi olmanın en iyi yolu sadece modelleme yönlerine odaklanmak değil, aynı zamanda bu modelin uygulanmasına neyin girdiğini anlamaktır. En zarif tasarım, kolayca uygulanamıyorsa veya sistemin daha büyük tasarımına veya diğer sistemlere uymuyorsa yararlıdır.
  • Çok az tasarım "doğru" veya "yanlış" tır. Tasarım sistemin gereksinimlerini karşıladığı sürece yanlış olamaz. Her gereksinimden, sistemin bu gereksinimi nasıl karşılayacağının bir gösterimi haline geldiğinde, tasarım yanlış olamaz. Bu noktada sadece esneklik veya tekrar kullanılabilirlik veya test edilebilirlik veya sürdürülebilirlik gibi kavramlar hakkında nitelikseldir.

Büyük tavsiye için teşekkürler, özellikle yanlış soyutlama düzeyinde olduğu gerçeği hakkında. Şimdi bunu GameTemplatedaha iyi hissettiren bir hale getirdim . Ayrıca beni ilklendir oyuncuları, tahta vb bir fabrika yöntemini birleştirmek sağlar
Mekswoll

3

Karışıklıklarınız haklı. Mesele şu ki, kalıplar birbirini dışlamıyor.

Şablon yöntemi, Strateji ve Devlet gibi bir dizi başka modelin temelini oluşturur. Temel olarak, Strateji arabirimi, her biri bir strateji uygulayan tüm nesnelerin (en azından) bir doAction () yöntemi gibi bir şeye sahip olmasını gerektiren bir veya daha fazla şablon yöntemi içerir. Bu, stratejilerin birbirinin yerine geçmesini sağlar.

Java'da bir arabirim bir dizi şablon yönteminden başka bir şey değildir. Benzer şekilde, herhangi bir soyut yöntem esasen bir şablon yöntemdir. Bu model (diğerleri arasında) dilin tasarımcıları tarafından iyi biliniyordu, bu yüzden onu inşa ettiler.

@ThomasOwens, sorununuza yaklaşmanız konusunda mükemmel tavsiyeler sunar.


0

Eğer tasarım desenleri dikkatiniz dağılmışsa, size tavsiyem ilk önce oyunu prototiplemek olacaktır, o zaman desenler sadece size atlamalıdır. Öncelikle bir sistemi mükemmel bir şekilde tasarlamayı ve sonra uygulamayı denemenin gerçekten mümkün veya tavsiye edilebilir olduğunu düşünmüyorum (benzer bir şekilde, insanlar önce tüm programları yazmaya ve derlemeye çalıştıklarında, daha sonra yavaş yavaş yapmayı şaşırtıcı buluyorum Sorun şu ki, mantığınızın uğraşması gereken her senaryoyu düşünmeniz pek olası değildir ve uygulama aşamasında ya tüm umudunuzu yitirecek ya da orijinal kusurlu tasarımınıza sadık kalmaya ve saldırıları tanıtmaya çalışacaksınız, hatta kötü hiç bir şey teslim.


2
İken , genel olarak sana katılıyorum , bu OP'ın sorunu çözen bir cevap gerçekten değil. "Bunu yapma" bir cevaptır, ancak uygulanabilir bir alternatif sunmuyorsa oldukça zayıf bir cevaptır.
yannis

@YannisRizos Ve kabul ederken size de (tavsiye doğru kelime değilse veya fikir), hala o ses tavsiyeler verdi düşünüyorum. Bu nedenle +1. Olsa da, evet teknik olarak çok yararlı bir cevap değil.
aldı777

-1

Pirinç meseleye inelim. Herhangi bir Oyun arayüzüne, tasarım desenine, soyut sınıflara ve UML'ye kesinlikle ihtiyaç yoktur.

Kullanıcı arayüzü, simülasyon ve her neyse, makul miktarda destek sınıfınız varsa, temel olarak oyun mantığına özgü olmayan kodunuz yine de yeniden kullanılır. Dahası, kullanıcınız oyununu dinamik olarak değiştirmez. Oyunlar arasında 30Hz'de çevirmezsiniz. Yaklaşık yarım saat boyunca bir oyun oynuyorsun. Yani "dinamik" polimorfizminiz aslında hiç de dinamik değil. Oldukça statik.

Buraya gitmenin mantıklı yolu, C # Actionveya C ++ gibi genel bir fonksiyonel soyutlama kullanmak std::function, bir Mancala, bir Wari ve bir Kalah sınıfı oluşturmak ve oradan gitmek.

std::unordered_map<std::string, std::function<void()>> games = {
    { "Kalah", [] { return Kalah(); } },
    { "Mancala", [] { return Mancala(); } },
    { "Wari", [] { return Wari(); } }
};
void play() {
    std::function<void()> f;
    f = games[GetChoiceFromUI()];
    f();
    if (PlayAgain()) return play();
}
int main() {
    play();
}

Bitti.

Oyunları aramazsınız. Oyunlar seni arar.


3
Bunun nasıl faydalı olduğunu anlamıyorum. Bu soruyu soran kişi bir öğrencidir. Tasarım ilkelerini ve iki tasarım deseni arasındaki etkileşimleri açıkça soruyor. Tasarım modellerine veya UML'ye ihtiyaç olmadığını söylemek endüstride bazı durumlarda doğru olabilir, ancak tasarım modellerini, tasarım modellerini ve UML'yi düşünmek, sorulan egzersizin noktası olabilir.
Thomas Owens

3
Onlar hakkında söylenecek bir şey yok, çünkü başvurdukları hiçbir yer yok. Onları nasıl kullanmamanız gerektiği konusunda bir ders olmayı düşünmüyorsanız, zamanınızı tasarım desenlerini kullanarak nasıl tamamen dolduracağınızı düşünmek için zaman harcamanın bir anlamı yoktur.
DeadMG

4
SoftDev'de kullanılan tasarım modellerinin sadece problemi çözmekten daha önemli olduğu düşünülen endişe verici / can sıkıcı bir eğilim var. Aşırı mühendislik diye bir şey var.
James

2
@DeadMG: Her ikiniz de haklıysanız OP'nin durumunda sorun sınavı geçiyor ve bu sorunun çözümü tasarım kalıpları ve UML kullanmak. Ne kadar doğru olursak olalım, eğer profesörü çözümlerine katılmazsa, geçemez.
Goran Jovic

2
Benim bütün hayatım hep Vay, "pirinç çiviler" yol daha mantıklı ... "pirinç vergisi" olduğunu düşündüm. lol
bought777
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.