August 13, 2012

Alıntı (Salih Dinçer):

>

Sanki MVC'nin çok büyük bir esprisi yok gibi.

MVC ile ilgili böyle görüşlere hiç rastlamamıştım. Belki daha yararını anlayamadık. Hangi kaynağı okumamı önerirsin?

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 19, 2012

Merhaba,

Geçen zaman içinde MVC hakkında, gereksizden öte saçma sapan bir şey olarak görmeye başladım! Çünkü programcıyı, kalıplaşmış bir yapı içinde sıkıştırıyor ve onu üç kategoriye göre seçim yapma zorunluluğunda bırakıyor. Bu ise zaman kaybı, stres ve kodu kalıba uygunlaştırma çabalarını beraberinde getiriyor.

Örneğin bu kodu bugün SDL2 ile tasarladım. Kodu yine parçalara böldüm ama kendimi zorlamadığım gibi kodu geliştirmeye başladım. Toplamda 4 dosyam oldu:

  • oyun.d
  • pencere.d
  • nesne.d
  • olaylar.d

Olaylar modülünde, şimdilik sadece klavye tuşlarını kontrol eden bir yapı var; bu önceki denememdeki control.d ile hemen hemen eşdeğer.

Pencere ve Nesne modülleri ise halen geliştirmeye açık iki yeni sınıf; içeriği model&view karışımı bir şey...

İlk dosya, bütün bunları çağıran 'main()' işlevinin ve 'while()' döngüsünün yer aldığı bölüm; içinde model de var, control de, view de...:)

Alıntı (Ali Çehreli):

>

Alıntı (Salih Dinçer):

>

Sanki MVC'nin çok büyük bir esprisi yok gibi.

MVC ile ilgili böyle görüşlere hiç rastlamamıştım. Belki daha yararını anlayamadık. Hangi kaynağı okumamı önerirsin?

Önerebileyeceğim tek kaynak: İnsan Psikolojisi...:)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 19, 2012

Salihcim bu konuda seninle aynı fikirde değilim. MVC tasarım deseni oyunlarda kullanılıyor.

http://www.loria.fr/~quinson/Teaching/CSH/TP-09.pdf

Ama maalesef sanırım sen benim daha önce yaptığım hataları yapıyorsun. Ben de ilk zamanlarda oyunu nasıl daha güzel kodlayabilirim, nasıl iyileştirmeler yapabilirim hatta senin de bahsettiğin tasarım desenlerini kullanabilirim diye düşünmüştüm. Aslında bu profesyonel oyun programcılarının bile yaptığı bir hataymış. Yani bazen öyle bir şey oluyor ki oyun kodlamak için kod yazmaya başlıyorsun. Sonra bir bakıyorsun 2D oyun motoru kodlamışsın! :-) Ama ortada oyun yok.

Hatta bu SDL projesinde bile ilk planda benim niyetim Ali beyin yazmış olduğu Pişti oyunu için grafiksel bir arabirim yazmaktı. Sonra bir baktım kendimi 2D grafik kütüphanesi kodlarken buldum.

Demek istediğim biraz çorba kod olsa da, ilk önceliğin kendine bir hedef belirleyip en kısa zamanda onu kodlamak olmalı. Örneğin bir Pacman olabilir, Tuğla Kırma olabilir vs.. Daha sonra oyunun nasıl programlanacağını öğrendiğin zaman artık hem istediğin programlama tekniklerini (sınıf tasarımını değiştirmek, tasarım desenlerini kullanmak) vs.. uygulayabilirsin hem de oyunu istediğin gibi değiştirebilirsin. Örneğin Pacman oyunu basit bir oyun gibi gözükür değil mi. Ama işin içine yapay zeka girerse hiç de kodlanması basit bir oyun olmadığı görülebilir.

Anlatmak istediğim çok iyi bir programcı olabilirsin. Ama programlama ile oyun programlama farklı şeyler.

Örneğin Gamemaker

http://www.yoyogames.com/make

Scirra gibi

http://www.scirra.com

oyun geliştirme ortamları var. Bunlarda programlama bilmeden oyun yapabiliyorsun. Bazı kişiler bunları önemsiz gibi görseler de oyunların çalışma mantığını anlamak açısından bence önemli.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 20, 2012

Alıntı (erdem):

>

Anlatmak istediğim çok iyi bir programcı olabilirsin. Ama programlama ile oyun programlama farklı şeyler.
Katılyorum...

Oyun programlama konusunda uzman olmak istemediğim gibi bunun zor olduğunu da düşünüyorum. Bunu daha önce "kırk fırın ekmek yemek" sözüyle betimlemeye çalışmıştım. Benim eleştirdiğim ve belki de anlamaya çalıştığım şeyler kalıplar...

Biliyorsunuz, herkesin ortak noktası bilgisayarlar. Hiç ilgili olmayan biri bile (bu çocuk olabilir) oyun sektörü içinde aynı noktada bizlerle buluşuyor. Ancak biz geliştirenler, ActionScript dahil bir çok farklı platform ve programlama dili tercih edebiliyorlar. Her bir programcının da farklı bir deseni olabiliyor. Kabaca söylediğim bütün bu değişkenleri birbirleriyle çarptığımızda bile çok fazla olasılık çıkıyor. Hatta olasılıkları veya programlama dillerini birlikte kullananlar da var...

Bu arada, Erdem'in yukarıda alıntıladığım sözüne bir ekleme yapmak aklıma geldi. Çok iyi oyun programcısı olabiliriz ama iyi bir oyun yazamayız. Çünkü oyun yazmak kollektif bir iş. Arabiriminden tutun da müzikler, en küçük grafikler bile bir sanat, bir uzmanlıktır. Dolayısıyla o sektörde bir iddiam yok ama baldan bir parmak çalıp bir şeyler kapma niyetim var. MVC konusu ne zamandır kafamdaydı ve onun sayesinde bana göre olmadığını anladım.

Hepsi bu...:)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 20, 2012

Öncelikle hakkını helal et hocam; bu kadar uzun iletiyi yazarken vakit harcattığım için. Çünkü bu vakit şu bayram günü sevdiklerinle geçireceğine bununla uğraşmana neden oldum...:blush:

Şimdi aşağıya yazacaklarım (tabi siz bu satırları okuduğunuz da yazdıklarım olacak!) real-time'dır...:)

  • Objektif olmalıydım ve tüm olumsuz düşüncelerimi bırakıp MVC'nin ruhuna uygun geliştirme yapmalıyım...
  • Evet, aklıma ekran dışına çıktığında verdiği hataya bakmak geldi.
  • İlk olarak boyaci.d dosyasını açtmalıyım çünkü seçimin gerçekleştiği bölüm burası. (controller olmalı?)
  • Ama önce tüm dosyaları Ali.tar.gz haline getirmeliyim. (iyiki hatırladım!)
  • Şimdi kağıt.d'deyim orada boya() diye bir işlev var ama nesne main()'de kurulmuş/ilklenmiş olmalı...
  • Evet öyleymiş! Zaten iki sürümün ortak noktası kağıt nesnesi ve şu satır boyacı.kullan(kağıt);
  • En başa döndüm ama buradan kağıt.d'ye bakayım şimdi burada iki döngü var biri MVC tekniği...
  • Sanırım boya() işlevinin döngüsü içinde bir if( ... < kareler.length) ile halledilebilir
  • Opps, bilgi eksikliği! Çift boyutlu dizilerde bunu nasıl yapacağımı bilimiyorum...:)
  • N'apıyoruz, hedef D.ershane (http://ddili.org/ders/d/diziler.html)...
  • Bulamadım ama pratik zeka ile denemeliydim: deneme[0].length.writeln; (diğer boyutu veriyor)
  • Olmadı...:(
       foreach (yer, renk; benekler) {
         if(yer.satır < kareler[0].length && yer.sütun < kareler.length) {
           kareler[yer.satır][yer.sütun] = renk;
         }
       }

Elbette bu ilk denememdi ve buraya kadar programcılık tecrübem ile alakalı. Ama Ali.tar.gz'yi oluşturduğu saate bakayım bir:

23:19 imiş...:)

Şu satırları yazdığım anda 23:54 ki yaklaşık yarım saattir uğraşıyorum. Birazdan bu iletiyi göndereceğim ama devam etmeliyim. Çünkü MVC'nin başka bir geliştirici için ne kadar iş kolaylaştırıcı olduğunu anlamaya çalışacağım. Hedefte yer.d dosyası var.

Son olarak Ali hocama böyle bir deneyimi yaşattığı için teşekkür ederim...

Dip Not: Bu arada denemenin ilk derlemesinde toplam 6 dosyayı (5906 byte/224 satır) söylendiği gibi ve Linux32 bitte ortamında derlendi. Yaklaşık 1 MB. dosya oluştu. Sanırım -gc ve -unittest parametreleri buna etkili oldu. Bu parametreleri çıkarınca yarı yarıya düştüğünü belirtmeliyim.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 20, 2012

boyacı.d modülüne bir üye eklemeyi ben de denedim ama kafam karışmış olacak ki length'in verdiği değeri / ilklenirken dönenleri x, y olarak eklemişim...:)

Vallahi ne yalan söyleyeyim (yalan değil... :-D) hala bir kaç sınıf arasında gidip geliyorum. Dedim ya belki tecrübe ile alakalı ama hep söylerim, "bir şeyi tablo gibi toplu görmekten hoşlanıyorum" diye...

Sanırım bu MVC bana çok ters çünkü lazım olan bir yapı (Yer) gitmiş başka dosyada. Orada kardeş kardeş dursalar ve programcıyı üç kategori ile kalıba sokmasalar olmuyor mu...:)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 20, 2012

Meğer satırla sütunu karıştırmışım! Çalışıyor...:)
Alıntı:

>

' 0| .....o.o..
1| .....o.o..
2| .....o.o..
3| .....o.o..
4| .....o.X..
'

if(yer.satır < kareler.length &&
  yer.sütun < kareler[0].length)
    kareler[yer.satır][yer.sütun] = renk;

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 20, 2012

Evet hocam, bu interface kümesini bilmiyorum ve okusam iyi olacak...:)

Hep açıklamalarda "observer pattern" dikkatimi çekti; ayrıca MVC arasında haberleşme ihtiyacı. Bunun için insan ek efor sarf ediyor gibime geliyor. Yine de körü körüne önyargılı değilim, anlamaya çalışıyorum...

..::: OKUDUM :::...
extern gibi bir şeymiş...:)

Biz extern'ü harici kütüphanelerdeki işlevleri/yapıları programımızda çağırabilmek için kullanıyoruz. Bu da dahili olanakların ondan türeyen tüm sınıflardan çağrılabilmesi içinmiş. Aslında buna türetmeden çok bağlama da diyebiliriz. Aynı yere/interface'e bağlanan sınıflar sanki birlikteymişler gibi birbirlerine bağlanıyor. Hoş bir özellikmiş, kullanmazsam ayıp olur...:D

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 20, 2012

Alıntı (Salih Dinçer):

>

Benim eleştirdiğim ve belki de anlamaya çalıştığım şeyler kalıplar.

Bunu kırıcı olmadan nasıl söyleyeceğimden emin değilim ama "eleştirme" ve "anlamaya çalışma" kavramlarını aynı cümlede kullanıyorsun. :) MVC'nin büyük bir esprisi olmadığını da bu konunun 9 numaralı mesajında söylemiştin. "MVC olayını öğrenelim" dedikten sonra daha sekiz saat bile geçmeden... :) Bence biraz yavaşlayalım ve önce olayı tam olarak anlayalım ve hatta biraz deneyim kazanalım; ondan sonra fikirlerimizi tartalım.

Ben MVC kalıbını uygulayanların körlemesine uyguladıklarını düşünmüyorum. Mutlaka bir yararı vardır. Aslında yararları tanımında açıkça geçiyor: Programın farklı işler yapan bölümlerini birbirlerinden ayırmak. Örneğin program mantığı verinin nasıl görüntülendiğini bilmezse ona lego parçası gibi farklı görüntüleyiciler bağlayabiliyoruz.

Alıntı:

>

programcıyı, kalıplaşmış bir yapı içinde sıkıştırıyor ve onu üç kategoriye göre seçim yapma zorunluluğunda bırakıyor.

O MVC'ye tamamen ters bir görüş. MVC'nin getirdiği yarar sıkıştırmak değil, tam tersine serbest bırakmaktır.

Ayrıca "kalıp" kavramıyla ilgili bir konuyu hatırlatmak istiyorum. Pattern denen bu kalıplar hiçbir zaman birileri oturup daha iyi olduğuna karar verdikleri için ortaya çıkmıyor. Bunlar başka insanların birbirlerinden bağımsız olarak keşfettikleri, yararlarını gördükleri, ve en sonunda da isimlendirdikleri olgulardır. Bir anlamda kalıplar kendiliklerinden ortaya çıkarlar.

Alıntı:

>

MVC konusu ne zamandır kafamdaydı ve onun sayesinde bana göre olmadığını anladım.

Haklı olabilirsin ama ben haddim olmayarak henüz iyi bir uygulamasıyla karşılaşmamış olduğun için öyle düşündüğünü düşünüyorum.

MVC için bir deneme de ben yapacağım. Hatırlayalım:

  • Model, programın asıl işini yürütüyor ve programdaki bilgilerin sahibi.

  • View, programın durumunun dışa vurumunu üstleniyor.

  • Controller, programın kullanıcısıyla etkileşimini hallediyor ve Model'ın değişmesini sağlıyor.

Örnek olarak Salih'in hatırlattığı İşlevler Bölümü'nün ikinci problemini düşünüyorum:

http://ddili.org/ders/d/islevler.html

Tabii oradaki program MVC ayrımı gözetilmeden yazılmıştır ve zaten kullanıcıyla etkileşim diye bir kaygısı da yoktur.

Model olarak oradan esinlendiğim şu Kağıt modülünden başlayalım:

class Kağıt {
   dchar[][] kareler;          // Kağıdı oluşturan kareler (tuval)
   Kağıtİlgilisi[] ilgililer;  // Bu kağıttaki değişiklerden haberdar olmak
                               // isteyen ilgililer (observers)

   this(size_t satırAdedi, size_t sütunAdedi, dchar zemin) {
       auto boşSatır = new dchar[sütunAdedi];
       boşSatır[] = zemin;

       foreach (i; 0 .. satırAdedi) {
           this.kareler ~= boşSatır.dup;
       }
   }

   // Bu, "observer pattern"da adı geçen registerObserver() işlevidir
   void ilgiliyiTanı(Kağıtİlgilisi ilgili) {
       this.ilgililer ~= ilgili;
   }

   // Kağıdı verilen beneklerle doldurur
   void boya(dchar[Yer] benekler) {
       foreach (yer, renk; benekler) {
           kareler[yer.satır][yer.sütun] = renk;
       }

       // Yeni benekler oluştuğunu ilgililere haber ver
       foreach (ilgili; ilgililer) {
           // Bu, "observer pattern"daki notify()'dır
           ilgili.değişti(kareler);
       }
   }
}

Üzerinde uzunca konuşmaya değecek bir sınıf değil. Sunduğu iki olanak var:

Birincisi, kağıdın durumunda değişiklik yapmayı sağlayan boya() işlevi. O işlev controller'ın bir kağıt nesnesini değiştirmesi için yeterlidir. Bu işlevin üzerinde durmaya gerek olmadığını düşünebiliriz. Herhalde nesnenin durumunda yapılan değişikliklerin bir üye işlev ile sağlanması gerektiğini artık kanıksamış olmalıyız. (Bunun alternatifi zararlı olabilir: Örneğin kullanıcılar 'noktalar' üyesine doğrudan da erişebilirler ve değiştirebilirlerdi.)

Sunduğu ikinci olanak da kendisine tanıştırılan Kağıtİlgilisi nesnelerini aklında tutması ve kendisinde oluşan değişiklikleri onlara haber vermesi. Bunu, boya()'nın en sonunda yapıyor.

Yukarıdaki Model'ın yararı şu: Bu sınıf yalnızca kendi işini biliyor. Ne kendisini kullananların ayrıntılarını biliyor ne de kendisiyle ilgilenenlerin ayrıntılarını.

Şimdi kağıt nesnelerini kullanmayı bilen bir controller'a bakalım:

class RasgeleBoyayan {
   size_t satırAdedi;
   size_t sütunAdedi;
   size_t rasgeleNoktaAdedi;

   this(size_t satırAdedi, size_t sütunAdedi, size_t rasgeleNoktaAdedi) {
       this.satırAdedi = satırAdedi;
       this.sütunAdedi = sütunAdedi;
       this.rasgeleNoktaAdedi = rasgeleNoktaAdedi;
   }

   void kullan(Kağıt kağıt) {
       dchar[Yer] noktalar;

       foreach (i; 0 .. rasgeleNoktaAdedi) {
           immutable yer = Yer(uniform(0, satırAdedi), uniform(0, sütunAdedi));
           immutable renk= 'a' + uniform(0, 26);
           noktalar[yer] = renk;
       }

       kağıt.boya(noktalar);
   }
}

Dışarıdan birisi ona "bu kağıdı kullan" diyor ve o da rasgele renkli noktalar oluşturarak kağıdı o noktalarla boyuyor. Kağıt hakkında tek bildiği, Kağıt.boya işlevi. Bu sınıfın da view nesnelerinden en ufak bir haberi yok. Tek yaptığı, model'da değişiklikler oluşturmak.

Son olarak bir view sınıfına bakalım:

class İkiBoyutluGösterici : Kağıtİlgilisi {
   void değişti(const dchar[][] noktalar) {
       foreach (i, satır; noktalar) {
           writefln("%3s| %s", i, satır);
       }
   }
}

Bu sınıf Kağıtİlgilisi arayüzünü gerçekleştiriyor. İkiBoyutluGösterici.değişti() işlevi Kağıt tarafından "ben değiştim" anlamında çağrılacak.

(Not: Değişiklikler başka biçimlerde de bildirilebilirdi. Ben örnek kısa olsun diye iki boyutlu dchar dizisini olduğu gibi geçirmeye karar verdim.)

Bu view sınıfı da çok yararlıdır: Ne model'dan haberi var ne de controller'dan. Tek bildiği, kendisine verilen değişiklikleri görüntülemek. (Tekrarlamak istiyorum: Bu view sanki kağıdın dchar[][] türündeki üyesinden haberliymiş gibi algılanmasın; kısa olsun diye öyle yaptım. Değişiklikleri bambaşka bir tür olarak da alabilirdi.)

Şimdi bu tasarımın getirdiği esnekliğe bakalım.

main() işlevi model, view, ve controller nesneleri oluşturarak onları birbirlerine tanıştırıyor ve programı işletiyor:

   // Model: Bir kağıt nesnesi oluşturuyoruz
   auto kağıt = new Kağıt(satırAdedi, sütunAdedi, zeminRengi);

   // View: İki farklı view nesnesini kağıda tanıtıyoruz
   kağıt.ilgiliyiTanı(new İkiBoyutluGösterici());
   kağıt.ilgiliyiTanı(new ListeleyenGösterici(zeminRengi));

   // Controller: Kağıtta değişiklikler yapacak olan nesneyi oluşturuyoruz
   enum rasgeleBenekAdedi = 10;
   auto boyacı = new RasgeleBoyayan(satırAdedi, sütunAdedi, rasgeleBenekAdedi);

   boyacı.kullan(kağıt);

O main kullanıldığında model iki farklı ilgili nedeniyle iki farklı biçimde görüntüleniyor:

'./mvc_deneme
0| .....q..q.
1| .........k
2| .........h
3| .r....r...
4| ...t...yx.

=== Zemin Renginde Olmayan Noktalar ===
0,5: q
0,8: q
1,9: k
2,9: h
3,1: r
3,6: r
4,3: t
4,7: y
4,8: x
'

Başka view ve controller nesneleri ise tamamen farklı bir program oluşturmaya yetecektir. Aşağıdaki programda iki farklı view ve iki farklı controller var. Bütün programı oluşturan dosyaları parçalar halinde buraya yazıyorum:

"boyaci.d" iki farklı controller'dan oluşuyor:

module boyaci;

import std.stdio;
import std.random;
import kagit;
import yer;

class RasgeleBoyayan {
   size_t satırAdedi;
   size_t sütunAdedi;
   size_t rasgeleNoktaAdedi;

   this(size_t satırAdedi, size_t sütunAdedi, size_t rasgeleNoktaAdedi) {
       this.satırAdedi = satırAdedi;
       this.sütunAdedi = sütunAdedi;
       this.rasgeleNoktaAdedi = rasgeleNoktaAdedi;
   }

   void kullan(Kağıt kağıt) {
       dchar[Yer] noktalar;

       foreach (i; 0 .. rasgeleNoktaAdedi) {
           immutable yer = Yer(uniform(0, satırAdedi), uniform(0, sütunAdedi));
           immutable renk= 'a' + uniform(0, 26);
           noktalar[yer] = renk;
       }

       kağıt.boya(noktalar);
   }
}

// Noktayı kağıt üzerinde yürütür; noktanın daha önceden geçtiği yerleri de
// belirtir.
class NoktaYürüten {
   enum uçRengi = 'X';
   enum gövdeRengi = 'o';

   Yer uç;

   this(Yer başlangıç) {
       this.uç = başlangıç;
   }

   void kullan(Kağıt kağıt) {
       kağıt.boya([ uç : uçRengi ]);

       writeln("Lütfen noktanın yolunu belirtiniz");

       bool devam_mı = true;

       while (devam_mı) {
           write("(w: Yukarı, z: Aşağı, a: Sola, s: Sağa, 0: Çıkış) ? ");
           dchar yön;
           readf(" %s", &yön);

           immutable eskiUç = uç;

           switch (yön) {
           case 'w': uç = uç.yukarıdaki; break;
           case 'z': uç = uç.aşağıdaki;  break;
           case 'a': uç = uç.soldaki;    break;
           case 's': uç = uç.sağdaki;    break;
           case '0': devam_mı = false;   break;
           default: writeln("Hatalı giriş!"); break;
           }

           kağıt.boya([ eskiUç : gövdeRengi, uç : uçRengi ]);
       }
   }
}

"gosterici.d" iki farklı view'dan oluşuyor:

module gosterici;

import std.stdio;
import kagit_ilgilisi;

// Kağıdın durumunu satır bilgileri halinde gösterir
class ListeleyenGösterici : Kağıtİlgilisi {
   dchar zeminRengi;

   this(dchar zeminRengi) {
       this.zeminRengi = zeminRengi;
   }

   void değişti(const dchar[][] noktalar) {
       writeln("\n=== Zemin Renginde Olmayan Noktalar ===");

       foreach (satır, satırNoktaları; noktalar) {
           foreach (sütun, renk; satırNoktaları) {
               if (renk != zeminRengi) {
                   writefln("%s,%s: %s", satır, sütun, renk);
               }
           }
       }
   }
}

// Kağıdı iki boyutlu olarak gösterir
class İkiBoyutluGösterici : Kağıtİlgilisi {
   void değişti(const dchar[][] noktalar) {
       foreach (i, satır; noktalar) {
           writefln("%3s| %s", i, satır);
       }
   }
}

"kagit.d" Kağıt türünü tanımlıyor:

module kagit;

import kagit_ilgilisi;
import yer;

class Kağıt {
   dchar[][] kareler;          // Kağıdı oluşturan kareler (tuval)
   Kağıtİlgilisi[] ilgililer;  // Bu kağıttaki değişiklerden haberdar olmak
                               // isteyen ilgililer (observers)

   this(size_t satırAdedi, size_t sütunAdedi, dchar zemin) {
       auto boşSatır = new dchar[sütunAdedi];
       boşSatır[] = zemin;

       foreach (i; 0 .. satırAdedi) {
           this.kareler ~= boşSatır.dup;
       }
   }

   // Bu, "observer pattern"da adı geçen registerObserver() işlevidir
   void ilgiliyiTanı(Kağıtİlgilisi ilgili) {
       this.ilgililer ~= ilgili;
   }

   // Kağıdı verilen beneklerle doldurur
   void boya(dchar[Yer] benekler) {
       foreach (yer, renk; benekler) {
           kareler[yer.satır][yer.sütun] = renk;
       }

       // Yeni benekler oluştuğunu ilgililere haber ver
       foreach (ilgili; ilgililer) {
           // Bu, "observer pattern"daki notify()'dır
           ilgili.değişti(kareler);
       }
   }
}

"kagit_ilgilisi.d" kağıttaki değişiklerden haberdar olmak isteyenlerin gerçekleştirmeleri gereken arayüzü bildiriyor:

module kagit_ilgilisi;

// Bu, "observer pattern"daki observer'dır.
//
// Kağıt'taki değişikliklerden haberdar olmak isteyenlerin gerçekleştirmeleri
// gereken arayüz. Kağıt, ilgilileri haberdan etmek için değişti() işlevini
// çağıracak.
interface Kağıtİlgilisi {
   // Bu, "observer pattern"daki notify() işlevidir.
   void değişti(const dchar[][] noktalar);
}

"yer.d" satır ve sütun bilgisinden oluşan ve bir kaç yararlı işlev sunan bir tür içeriyor:

module yer;

struct Yer
{
   size_t satır;
   size_t sütun;

   Yer yukarıdaki() const @property {
       return Yer(satır - 1, sütun);
   }

   Yer aşağıdaki() const @property {
       return Yer(satır + 1, sütun);
   }

   Yer sağdaki() const @property {
       return Yer(satır, sütun + 1);
   }

   Yer soldaki() const @property {
       return Yer(satır, sütun - 1);
   }
}

"main.d" MVC tasarımının getirdiği esnekliği göstermek için birisi -version seçeneği ile seçilebilen iki farklı main() içeriyor:

module main;

import std.stdio;
import kagit;
import gosterici;
import boyaci;
import yer;

enum satırAdedi = 5;
enum sütunAdedi = 10;
enum zeminRengi = '.';

version (etkiles) {

void main()
{
   // Model: Bir kağıt nesnesi oluşturuyoruz
   auto kağıt = new Kağıt(satırAdedi, sütunAdedi, zeminRengi);

   // View: Bir view nesnesini kağıda tanıtıyoruz
   auto gösterici = new İkiBoyutluGösterici();
   kağıt.ilgiliyiTanı(gösterici);

   // Controller: Kağıtta değişiklikler yapacak olan nesneyi oluşturuyoruz
   immutable ortaNokta = Yer(satırAdedi / 2, sütunAdedi / 2);
   auto boyacı = new NoktaYürüten(ortaNokta);

   boyacı.kullan(kağıt);
}

} else { // version

void main()
{
   // Model: Bir kağıt nesnesi oluşturuyoruz
   auto kağıt = new Kağıt(satırAdedi, sütunAdedi, zeminRengi);

   // View: İki farklı view nesnesini kağıda tanıtıyoruz
   kağıt.ilgiliyiTanı(new İkiBoyutluGösterici());
   kağıt.ilgiliyiTanı(new ListeleyenGösterici(zeminRengi));

   // Controller: Kağıtta değişiklikler yapacak olan nesneyi oluşturuyoruz
   enum rasgeleBenekAdedi = 10;
   auto boyacı = new RasgeleBoyayan(satırAdedi, sütunAdedi, rasgeleBenekAdedi);

   boyacı.kullan(kağıt);
}

} // version

Derlemek için:

'dmd boyaci.d gosterici.d kagit.d kagit_ilgilisi.d main.d yer.d -ofmvc_deneme -unittest -property -w -gc -debug '

O satır yukarıda verdiğim çıktıyı üretir. Aşağıdaki satır ise kullanıcının programla etkileştiği ve ekranda yılan gibi ilerletebildiği bir nokta oluşturur (Ekran dışına çıkıldığında hata atıyor; kısa olsun diye onlarla ilgilenmedim):

'dmd ... -version=etkiles'

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 20, 2012

Alıntı (Salih Dinçer):

>

Öncelikle hakkını helal et hocam; bu kadar uzun iletiyi yazarken vakit harcattığım için.

Ne demek! Sen bu konuyu açmasaydın ben de bu deneyimi edinemezdim. :)

Alıntı:

>
>         foreach (yer, renk; benekler) {
>           if(yer.satır < kareler[0].length && yer.sütun < kareler.length) {
>             kareler[yer.satır][yer.sütun] = renk;
>           }
>         }
> ```


Ben de aynen öyle yapmaya başlamış ama sıfır indeksli satırın bulunmayabileceğini düşündüğüm için boşvermiştim. Çözüm olarak kurucu işlevde satır adedi olarak sıfırı reddedebilirdim ama işler karmaşıklaşacaktı.

Onun için sütunAdedi diye bir üye değişken eklemek daha iyi:


   foreach (yer, renk; benekler) {
       if ((yer.satır < kareler.length) &&
           (yer.sütun < sütunAdedi)) {  // <-- sütunAdedi yeni üye
           kareler[yer.satır][yer.sütun] = renk;
       }
   }


Ali

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]