Program mimarisi nedir. Java'daki MVC Tasarım Modeli nedir?

Bu öğreticide, SPL (Standart PHP Kitaplığı, PHP Standart Kitaplığı) özelliklerini kullanarak PHP 5.1'de basit bir MVC (Model-View-Controller) sisteminin nasıl oluşturulacağını öğreneceksiniz.

giriiş

PHP 5 için ilk tam eğitime hoş geldiniz. En son PHP 5 özelliklerinden bazılarını kullanacağımız için SPL kitaplığı kuruluyken PHP 5.1'e ihtiyacınız olacak.

Bu derste size basit bir MVC sisteminin nasıl oluşturulacağını göstereceğim (MVC mimarisi, büyük web uygulamaları için en yaygın tasarım modelidir). Eksiksiz bir MVC sistemi oluşturmak için baştan sona tüm adımlarda size yol göstereceğim.

Bir giriş noktası

MVC ile ilgili önemli şeylerden biri, şöyle bir şey yapan bir grup PHP dosyası yerine uygulamaya tek bir giriş noktasıdır:

Tüm istekleri ele alan bir dosyamız olacak. Bu, her yeni sayfa oluşturmamız gerektiğinde global.php'yi dahil etme konusunda endişelenmemize gerek olmadığı anlamına gelir. Bu "tek giriş noktası" index.php olarak adlandırılacak ve şimdilik şöyle olacak:

Gördüğünüz gibi bu script henüz bir şey yapmıyor ama bir dakika bekleyin.

Tüm istekleri ana sayfaya yönlendirmek için mod_rewrite kullanacağız ve .htaccess içinde RewriteRule yönergesini ayarlayacağız. Aşağıdaki kodu .htaccess dosyasına yapıştırın ve index.php ile aynı dizine kaydedin:

RewriteCond'da RewriteEngine %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule ^(.*)$ index.php?route=$1

İlk olarak, RewriteCond yönergesini kullanarak istenen dosyanın var olup olmadığını kontrol ederiz, yoksa isteği index.php'ye yönlendiririz. Dosyanın mevcudiyeti için bu kontrol gereklidir çünkü aksi takdirde index.php, resim istekleri de dahil olmak üzere siteye gelen tüm istekleri işlemeye çalışacaktır. Ve bu sadece ihtiyacımız olmayan şey.

.htaccess veya mod_rewrite kullanamıyorsanız, tüm istekleri manuel olarak index.php'ye yönlendirmeniz gerekecektir. Diğer bir deyişle, tüm bağlantılar "index.php?route=[request-goes-buraya]" biçiminde olmalıdır. Örneğin, "index.php?route=chat/index".

Artık tüm istekler aynı giriş noktasından geçtiğine göre, index.php betiğini yazmaya başlayabiliriz. Yapmamız gereken ilk şey, sistemi başlatmak. İçerir dizinini ve onun içinde startup.php dosyasını (bizim başlatma dosyamız olacak) oluşturalım. Aşağıdaki kodu index.php'ye yapıştırın:

Bu örnekte, bir sabit tanımladık, sistem dosyalarının nerede olduğunu bulduk ve ayrıca PHP sürümünün en az 5.1 olup olmadığını kontrol ettik.

Bundan sonra yapılacak şey, global değerleri tutan bir Registry nesnesidir. Bireysel sistem nesnelerine geçirilecek ve değişkenleri "global" olarak atamak veya $GLOBALS dizisine başvurmak zorunda kalmadan global değerlere erişmek için kullanılacaktır. Kayıt nesnesi hakkında daha fazla bilgi için "PHP'de Global Değerleri Kullanma" makalesini okuyun.

Önceki örnekteki kodun arkasına aşağıdaki kodu startup.php dosyasına ekleyin:

$registry = yeni Kayıt;

Sistemi şimdi başlatmayı denerseniz, aşağıdaki hatayı görebilirsiniz:

Önemli hata: "Kayıt Defteri" sınıfı, 12. satırda g:\Projects\PHP\content\simple mvc php5\demo\includes\startup.php içinde bulunamadı

Bu elbette bizim için büyük bir sürpriz değil çünkü henüz Registry sınıfının kendisini yazmadık. Sınıf dosyası, include() işlevi kullanılarak dahil edilebilir. PHP 5'teki yeni özelliklerden birini kullanalım: __autoload().

Sihirli işlev __autoload(), sınıfları dinamik olarak yüklemek için kullanılır. PHP var olmayan bir sınıf algıladığında, önce __autoload() işlevini çağırır ve ancak o zaman bir hata atar. Sınıfları anında yüklemek için bu fırsattan yararlanabiliriz.

Bu kodu önceki örnekteki kodun önüne yapıştırın:

// Sınıfları anında yükle fonksiyonu __autoload($class_name) ( $filename = strtolower($class_name) . ".php"; $file = site_path . "classes" . DIRSEP . $filename; if (file_exists($file) = = false) ( false döndür; ) include ($file); )

__autoload() işlevimiz, kendisine argüman olarak iletilen sınıf adını alır ve sınıflar dizininde benzer bir ada sahip bir dosya olup olmadığını kontrol eder. Dosya yoksa, işlev yalnızca false döndürür ve önemli bir hata açılır. Ancak dosya varsa, yüklenecektir. Şunlar. gerekli sınıf bildirilecek ve herhangi bir hata olmayacaktır.

Henüz Registry sınıfını oluşturmadık, bu nedenle hata görünmeye devam edecek. Şuna devam edelim.

Registry sınıfının oluşturulması

Registry sınıfı, tek tek nesneler arasında global değerleri iletmek için kullanılır. Aslında birkaç küçük yöntem uygulaması gereken oldukça basit bir sınıftır.

İlk olarak sınıflar dizinini ve içinde kayıt defteri.php dosyasını oluşturalım. Aşağıdaki kodu register.php'ye yapıştırın:

Şimdi Registry sınıfının bir "iskeleti"ne sahibiz ve onu yöntemlerle yüklememiz gerekiyor. 2 metot yazalım: değerleri ayarlamak için set() ve değerleri almak için get(). Değerleri kaldırmak için bir remove() yöntemi de yazabilirsiniz. Bu yöntemleri Registry sınıfına ekleyelim:

fonksiyon set($key, $var) ( if (isset($this->vars[$key]) == true) ( ​​yeni İstisna atmak("var `" . $anahtar . "`. Zaten ayarlanamadı. set. "); ) $this->vars[$key] = $var; return true; ) function get($key) ( if (isset($this->vars[$key]) == false) ( return null; ) return $this->vars[$key]; ) function remove($var) ( unset($this->vars[$key]); ) ?>

Bu yöntemler basittir, sınıfın bir özniteliği olan $vars dizisinden öğeleri ayarlar, alır ve kaldırırlar. set() yönteminde, belirtilen anahtara sahip bir değerin zaten var olup olmadığını da kontrol ederiz ve varsa bir istisna atarız. Bu, değerlerin yanlışlıkla üzerine yazılmasını önlemek için gereklidir.

Artık tam teşekküllü bir Kayıt sınıfımız var, ancak burada durmayacağız. SPL kitaplığının özelliklerinden birini kullanalım: ArrayAccess. SPL (Standart PHP Kitaplığı'nın kısaltması), yaygın sorunları çözmek için tasarlanmış bir arayüzler ve sınıflar topluluğudur. SPL arabirimlerinden biri olan ArrayAccess, normal bir dizi gibi bir nesneye erişim sağlamak için kullanılabilir. Şu örneğe bakalım:

set("isim", "Dennis Pallett"); // değeri get() echo $registry->get ("name"); // Dizi erişimini kullanarak değer alın echo $registry["name"] ?>

İşin püf noktası, $registry'nin aslında bir nesne olmasına rağmen bir dizi gibi olmasıdır. Elbette, ArrayAccess herhangi bir özel avantaj sağlamaz, ancak her seferinde "->get ()" yazmanız gerekmediğinden kod miktarını azaltmanıza olanak tanır. Bu arayüzü kullanmak için sınıfın ilk satırını ("Sınıf Kayıt Defteri") aşağıdaki gibi düzeltmeniz gerekir:

Sınıf Kayıt Defteri Dizi Erişimini Uygular (

"Implements" anahtar sözcüğü, yorumlayıcıya, bu sınıfla bir arabirim uyguladığımızı söyler; bu, ArrayAccess'in gerçekte olduğu şeydir.

ArrayAccess arabirimini uygulayan bir sınıf aşağıdaki yöntemlere sahip olmalıdır:

function offsetExists($offset) ( return isset($this->vars[$offset]); ) function offsetGet($offset) ( return $this->get($offset); ) function offsetSet($offset, $değer) ( $this->set($offset, $value); ) function offsetUnset($offset) ( unset($this->vars[$offset]); )

Bu yöntemler kendi kendini açıklayıcı olmalıdır. Daha fazla bilgi SPL belgelerinde bulunabilir.

Şimdi, ArrayAccess arabirimini uyguladıktan sonra, nesneye sıradan bir diziymiş gibi erişebiliriz. Bu, hem önceki örnekte hem de bu örnekte açıkça gösterilmiştir:

get("isim"); // Dizi erişimini kullanarak değer alın echo $registry["name"] ?>

Registry sınıfı şimdi tamamlandı ve sistemi başlatmaya çalışırsanız, her şey çalışmalıdır (henüz hiçbir şey çıkmayacak olsa da). Başlatma dosyasıyla işimiz bittiğinde, MVC sistemimizi yazarken bir sonraki adıma geçmeye hazırız: MVC mimarisinde "Model" olarak adlandırılan veritabanı erişimini uygulamak.

modeli

"M" veya model, MVC sisteminin veritabanını (veya diğer harici kaynağı) sorgulamaktan ve denetleyiciye bilgi sağlamaktan sorumlu olan parçasıdır. İsteğe bağlı olarak gerekli modeli yüklemek mümkün olabilir ama ben bu yerde model ile controller arasındaki sınırları biraz bulanıklaştırmayı tercih ediyorum, yani. denetleyici, ayrı bir model yerine doğrudan veritabanı etkileşim kitaplığı aracılığıyla veritabanıyla çalışır. Belki farklı yapmak istersiniz, bu bir zevk meselesi.

Veritabanı bağlantısı kurmak için gerekli olan kodu yazıp index.php içerisine yerleştirmemiz gerekiyor. Dışarıda pek çok harika veritabanı kitaplığı var (kendime ait AutoCRUD dahil), ancak PHP 5'te zaten bir tane PDO var. Bu nedenle, başka bir kullanmaya gerek yoktur.

Aşağıdaki kodu index.php dosyasına yapıştırın (başlatma dosyasını ekledikten sonra):

# Veritabanına bağlanın $db = new PDO("mysql:host=localhost;dbname=demo", "", ""); $kayıt->set("db", $db);

Bu örnekte, önce PDO kitaplığının yeni bir örneğini oluşturuyoruz ve MySQL veritabanımıza bağlanıyoruz. Ardından, Registry sınıfımızı kullanarak $db değişkenini global olarak kullanılabilir hale getiriyoruz.

Sistemimizin model bileşeni hazır, o halde şimdi controller'ı yazmaya geçelim.

Bir denetleyici yazmak, isteğe bağlı olarak istenen denetleyiciyi yüklemekten sorumlu olan Router sınıfını yazmak anlamına da gelir (unutmayın, index.php'de $route değişkeni URL'den geçirilir).

yönlendirici sınıfı

Yönlendirici sınıfı, isteği ayrıştırır ve ardından gerekli denetleyiciyi yükler. Sınıfın bir "iskeletini" oluşturalım:

kayıt defteri = $kayıt defteri; ) ) ?>

Ardından index.php dosyasına aşağıdaki satırları ekleyin:

# Yönlendiriciyi yükle $yönlendirici = yeni Yönlendirici($registry); $registry->set("yönlendirici", $yönlendirici);

Yazacağımız ilk şey, tüm denetleyicilerimizin olacağı dizini ayarlamak için setPath() yöntemidir. Yöntem şöyle görünür ve Router sınıfına eklenmelidir:

İşlev setPath($path) ( $path = trim($path, "/\\"); $path .= DIRSEP; if (is_dir($path) == false) ( yeni İstisna at ("Geçersiz denetleyici yolu: ` " . $yol . "`"); ) $bu->yol = $yol; )

Ardından index.php dosyasına aşağıdaki satırları ekleyin:

$router->setPath(site_path . "kontrolörler");

Denetleyicilerimizin yolunu belirlediğimize göre, denetleyiciyi yüklemekten sorumlu olan yöntemi yazalım. Bu yöntem delege() olarak adlandırılacak ve isteği ayrıştıracaktır. Bu yöntemin ilk parçası:

İşlev delegesi() ( // $this->getController($file, $controller, $action, $args) yolunu ayrıştırın;

Gördüğünüz gibi, denetleyicinin adını ve diğer birkaç değişkeni almak için getController() adlı başka bir yöntem kullanıyor. Bu yöntem şöyle görünür:

Özel işlev getController(&$file, &$controller, &$action, &$args) ( $route = (empty($_GET["route"])) ? "" : $_GET["route"]; if ( boş($route)) ( $route = "index"; ) // Bölünmüş parçaları al $route = trim($route, "/\\"); $parts = patlat("/", $route); // Doğru denetleyiciyi bulun $cmd_path = $this->path;foreach ($parts as $part) ( $fullpath = $cmd_path . $part; // Bu yola sahip bir klasör var mı? if (is_dir($fullpath)) ( $cmd_path .= $part .DIRSEP; array_shift($parts); devam; ) // Dosyayı bulun if (is_file($fullpath . ".php")) ( $controller = $part; array_shift($parts); break ; ) ) if (empty($denetleyici)) ( $denetleyici = "dizin"; ); // İşlemi al $eylem = array_shift($parçalar); if (boş($eylem)) ( $eylem = "dizin"; ) $dosya = $cmd_path .$denetleyici .".php"; $args = $parçalar; )

Bu yöntemin üzerinden geçelim. Önce istekten $route değişkeninin değerini alır, ardından patlat() işlevini kullanarak onu parçalara ayırır. Örneğin, "üyeler/görünüm" sorgusu şöyle bir diziye dönüştürülür: dizi('üyeler', 'görünüm').

Daha sonra her parçadan bir foreach döngüsü ile geçer ve o parçanın bir dizin olup olmadığını kontrol eder. Eğer öyleyse, onu dosyanın yoluna ekler ve sonraki kısmı kontrol eder. Bu, denetleyicileri alt dizinlere koymanıza ve böylece bir denetleyici hiyerarşisi elde etmenize olanak tanır. İsteğin mevcut kısmı bir dizin değil de bir dosyaysa, $controller değişkeninde saklanır ve ihtiyacımız olan controller bulunduğu için döngüden çıkarız.

Döngüden sonra controller ismi ile değişkeni kontrol ediyoruz. Boşsa, varsayılan denetleyicimiz olacak "indeks" denetleyicisini kullanırız. Yöntem daha sonra gerçekleştirilecek eylemi tanımlar. Denetleyici, birkaç yöntemden oluşan bir sınıftır. Bir eylem, belirli bir yönteme işaret eder. Eylem belirtilmemişse, varsayılan eylem olan "index" kullanacağız.

Ve son olarak, üç değişkeni birleştirerek denetleyici dosyasının tam yolunu elde ederiz: yol, denetleyici adı ve "php" uzantısı.

Artık isteği ayrıştırdığımıza göre, denetleyiciyi yüklemek ve eylemi gerçekleştirmek için delege() yöntemini çağırmanın zamanı geldi. Tam delege() yöntemi şöyle görünür:

İşlev delegesi() ( // $this->getController($file, $controller, $action, $args) yolunu ayrıştırın; // Dosya kullanılabilir mi? if (is_readable($file) == false) ( die ( "404 Bulunamadı"); ) // include ($file) dosyasını dahil et; // Denetleyicinin bir örneğini oluştur $class = "Controller_" . $controller; $controller = new $class($this->registry) ; // İşlem mevcut mu? if (is_callable(array($controller, $action)) == false) ( die ("404 Bulunamadı"); ) // $controller->$action(); ) işlemini gerçekleştirin

İsteği getController() yöntemiyle ayrıştırdıktan sonra dosyanın gerçekten var olup olmadığını kontrol ederiz ve yoksa basit bir hata mesajı döndürürüz.

Bundan sonra, dosyayı denetleyiciye dahil ediyoruz ve "Controller_[name]" olarak adlandırılması gereken sınıfının bir örneğini oluşturuyoruz. Biraz sonra kontrolörler hakkında daha ayrıntılı konuşacağız.

Ardından belirtilen eylemin (yani yöntemin) var olup olmadığını ve çağrılabilir olup olmadığını kontrol ederiz (bunun için is_callable() işlevini kullanırız). Son olarak, Router sınıfının rolünün bittiği eylemin kendisini gerçekleştiriyoruz.

Tam delege() yöntemini yazdıktan sonra, index.php dosyasına aşağıdaki satırı ekleyin:

$yönlendirici->temsilci();

Sistemi şimdi başlatmaya çalışırsak, aşağıdaki hatayı göreceğiz (tabii, henüz controllers dizini yoksa):

Önemli hata: g:\Projects\PHPit\content\simple mvc php5\demo'da "Geçersiz denetleyici yolu: `g:\Projects\PHP\content\simple mvc php5\demo\controllers\`" mesajıyla yakalanmayan "İstisna" \classes\router.php:18 Yığın izleme: #0 g:\Projects\PHP\content\simple mvc php5\demo\index.php(13): Router->setPath("g:\Projects\PHP... ") 18. satırda g:\Projects\PHP\content\simple mvc php5\demo\classes\router.php içine atılan #1 (ana)

Aksi takdirde henüz kontrolcü olmadığı için “404 Bulunamadı” hatası ile karşılaşacağız. Ama şimdi yapacağımız şey bu.

Denetleyici

MVC sistemimizdeki kontrolörler oldukça basit olacak ve çok az zaman alacaktır. İlk olarak, controllers dizininin var olduğundan emin olun. sınıflar dizininde bir controller_base.php dosyası oluşturun ve aşağıdaki kodu içine yapıştırın:

kayıt defteri = $kayıt defteri; ) soyut fonksiyon indeksi(); ) ?>

Bu soyut sınıf, tüm denetleyicilerimiz için ana sınıf olacaktır. Yalnızca iki şey yapacaktır: Registry sınıfının yerel bir kopyasını tutmak ve tüm alt denetleyicileri bu yöntemi uygulamaya zorlamak için abstract index() yöntemini kullanmak.

İlk controller'ımızı yazalım. Controller dizininde bir index.php dosyası oluşturun ve aşağıdaki kodu içine yapıştırın:

Az önce ilk controller'ımızı oluşturduk ve sistemi başlatmaya çalışırsak aşağıdakileri görebiliriz:

Bu, Router sınıfının işini yaptığı ve gerekli kontrol cihazından gerekli eylemi başlattığı anlamına gelir. "üyeler/görüntüleme" isteğiyle eşleşecek başka bir controller yazalım. controllers dizininde bir üye.php dosyası oluşturun ve aşağıdaki kodu içine yapıştırın:

Şimdi "members/view" veya "index.php?route=members/view" isteği ile MVC sistemimize gidelim. Şu sonucu görmeliyiz:

Sadece yeni bir controller yazıp ona bir metot ekleyerek, sistemin kendisinde hiçbir şeyi değiştirmeden yeni bir sayfa oluşturabildik. Ayrıca, denetleyicilerimizin bir global.php dosyası veya bunun gibi bir şey içermesine gerek yoktur.

Artık kontrolörlerimiz olduğuna göre, geriye tek bir şey kaldı: "V" veya "Görünüm".

Görüntülemek

Modellerde olduğu gibi, bir MVC sisteminde bir Görünüm bileşeni oluşturmak için birkaç farklı seçenek vardır. Router sınıfına "view_(name).php" gibi başka bir dosyayı otomatik olarak yüklemesini öğretebiliriz. Ancak kılavuzu daha anlaşılır kılmak için, şablonların çıktısını işleyecek bir Template sınıfı yazalım.

Öncelikle classlar dizininde bir template.php dosyası oluşturalım ve içine aşağıdaki kodu yapıştıralım:

kayıt defteri = $kayıt defteri; ) ) ?>

Artık Template sınıfımızın ana yapısına sahibiz. Bir sonraki adım, Router sınıfı ile ilgili satırlardan hemen önce index.php dosyasına aşağıdaki kodu eklemektir:

# Bir şablon nesnesi oluşturun $template = new Template($registry); $kayıt->set("şablon", $şablon);

Modellerden ve denetleyicilerden gelen değerleri kullanmamız gerekeceğinden, şablonlarda bulunan değişkenleri ayarlamak için bir set() yöntemi yazacağız. Bir örneğe bakalım:

İşlev set($varname, $değer, $overwrite=false) ( if (isset($this->vars[$varname]) == true AND $overwrite == false) ( trigger_error ("var `" ayarlanamıyor . $varname . "`. Zaten ayarlanmış ve üzerine yazmaya izin verilmiyor.", E_USER_NOTICE); return false; ) $this->vars[$varname] = $value; return true; ) function remove($varname) ( unset($ this->vars[$varname]); true döndür; )

set() ve remove() yöntemleri oldukça basittir ve sırasıyla değişkenleri ayarlamak ve kaldırmak için kullanılır.

Şablonları gösterecek olan show() metodunu yazalım. En kolay yol, tüm şablon dosyalarının depolandığı ayrı bir şablon dizini oluşturmak ve şablonun çıktısını almak için include() işlevini kullanmaktır. Elbette, kendi show() yönteminiz tamamen farklı olabilir ve şablonları veritabanından yükleyebilir veya başka bir şey yapabilir. Kuso'ya bakalım.

Oylar: 745 | Görüntüleme: 8082

İyi günler sevgili meslektaşlarım. Bu yazıda MVC, MVP ve MVVM kalıpları arasındaki farklara dair analitik anlayışımdan bahsetmek istiyorum. Bu makaleyi, büyük yazılımların geliştirilmesine ve buna karşılık gelen mimari özelliklere ilişkin modern yaklaşımları anlama arzusundan ilham aldım. Kariyer basamaklarımın şu anki aşamasında, doğrudan geliştirici değilim, bu nedenle makale hatalar, yanlışlıklar ve yanlış anlamalar içerebilir. Analistlerin programcıların ve mimarların ne yaptığını nasıl gördüğünü merak mı ediyorsunuz? O zaman kedinin altına hoşgeldin.

Bağlantılar
Başlamak istediğim ilk şey, bu makaleyi yazma sürecinde bana rehberlik eden harici materyallere bağlantılar:
giriiş
Güneşin daha parlak parladığı ve çimlerin daha yeşil olduğu bir dönemde, bu makalenin yazarı gibi bir öğrenci ekibi, yüzlerce satır kodu doğrudan ürünün arayüzüne yazarak bir yazılım geliştirdi. Bazen servisler ve yöneticiler verilerle çalışmak için kullanıldı ve daha sonra Belge-Görünüm modeli kullanılarak çözüm elde edildi. Bu tür bir kodun desteklenmesi çok büyük maliyetler gerektiriyordu, çünkü yeni bir geliştiricinin üründeki neyden hangi kodun sorumlu olduğunu eğitmesi (söylemesi) gerekiyordu ve herhangi bir birim testi söz konusu değildi. Geliştirme ekibi aynı odada oturan 4 kişidir.
Zaman geçti, işler değişti. Geliştirilmekte olan uygulamalar, uyumlu bir geliştirme ekibinden birçok farklı geliştirici, mimar, kullanılabilirlik uzmanı, tasarımcı ve PM ekibine kadar daha büyük ve daha karmaşık hale geldi. Artık herkes kendi alanından sorumludur: GUI, iş mantığı, bileşenler. Bir analiz, test, mimari bölümü vardı. Yazılım geliştirmenin maliyeti yüzlerce hatta binlerce kat arttı. Bu geliştirme yaklaşımı, ürünün farklı işlevsel alanlarını birbiriyle senkronize edecek istikrarlı bir mimari gerektirir.
desenler
Karmaşık yazılımların geliştirilmesi için işgücü maliyetlerini azaltma hedefi göz önüne alındığında, hazır birleşik çözümlerin kullanılmasının gerekli olduğunu varsayalım. Sonuçta, eylem modeli geliştiriciler arasındaki iletişimi kolaylaştırır, iyi bilinen yapılara başvurmanıza izin verir ve hata sayısını azaltır.
Wikipedia'ya göre, bir kalıp (İngilizce tasarım kalıbı), sık sık meydana gelen bir bağlamda bir tasarım sorununa çözüm olan tekrarlanabilir bir mimari tasarımdır.

İlk ana olanla başlayalım - Model-View-Controller. MVC, birçok teknolojide uygulama bulan, yeni teknolojilerin ortaya çıkmasını sağlayan ve geliştiricilerin hayatını her gün kolaylaştıran temel bir kalıptır.

MVC modeli ilk olarak SmallTalk dilinde ortaya çıktı. Geliştiricilerin, grafik arayüzü iş mantığından ve iş mantığını verilerden ayıracak bir mimari çözüm bulması gerekiyordu. Böylece klasik versiyonda MVC, adını veren üç bölümden oluşuyor. Onları düşünün:

modeli
Model genellikle uygulamanın işlevsel iş mantığını içeren bir parça olarak anlaşılır. Model, ürünün geri kalanından tamamen bağımsız olmalıdır. Model katmanının tasarım öğeleri ve nasıl oluşturulacağı hakkında hiçbir şey bilmesine gerek yoktur. Modelin kendisine dokunmadan verilerin sunumunu, nasıl görüntülendiklerini değiştirmenize izin veren bir sonuç elde edilir.

Model aşağıdaki özelliklere sahiptir:

  • Model, uygulamanın iş mantığıdır;
  • Modelin kendisi hakkında bilgisi vardır ve denetleyiciler ve görünümler hakkında bilgi sahibi değildir;
  • Bazı projeler için model yalnızca bir veri katmanıdır (DAO, veritabanı, XML dosyası);
  • Diğer projeler için bir model, bir veritabanı yöneticisi, bir nesneler topluluğu veya basitçe uygulama mantığıdır;
görüş
Görünümün sorumluluğu, Modelden alınan verileri görüntülemektir. Ancak, görünüm modeli doğrudan etkileyemez. Bir görünümün verilere salt okunur erişimi olduğu söylenebilir.

Görünüm aşağıdaki özelliklere sahiptir:

  • Görünüm, modelden elde edilen verilerin herhangi bir şekilde görüntülenmesini uygular;
  • Bazı durumlarda, bir görünüm, bazı iş mantığını uygulayan koda sahip olabilir.
Örnekleri görüntüleyin: HTML sayfası, WPF formu, Windows Formu.
Farklılıklar MVP & MVVM & MVP
En yaygın MVC modeli türleri şunlardır:
  • Model-Görünüm-Denetleyici
  • Model-Görünüm-Sunucu
  • Model-Görünüm-Görünüm Modeli

Her birini düşünün ve karşılaştırın.

Model-Görünüm-Sunucu

Bu yaklaşım, görünümün bir soyutlamasını oluşturmanıza olanak tanır. Bunu yapmak için, belirli bir dizi özellik ve yöntemle görünüm arayüzünü vurgulamanız gerekir. Sunucu, sırayla, arayüzün uygulanmasına bir referans alır, olayları görüntülemek için abone olur ve talep üzerine modeli değiştirir.

Sunucu Özellikleri:

  • Görünüm, sunucu örneğindeki uygun işlevleri veya olayları çağırarak doğrudan sunucuyla etkileşime girer;
  • Sunucu, Görünüm tarafından uygulanan özel bir arabirim kullanarak Görünüm ile etkileşime girer;
  • Bir sunucu örneği, bir görünümle ilişkilendirilir.

Uygulama:
Her görünüm, karşılık gelen arabirimi uygulamalıdır. Görünüm arayüzü, kullanıcı etkileşimi için gereken bir dizi işlevi ve olayı tanımlar (örneğin, iView.ShowErrorMessage(dize msj)). Sunucu, genellikle yapıcıda iletilen ilgili arabirimin uygulanmasına ilişkin bir referansa sahip olmalıdır.
Sunum mantığının, sunucu örneğine bir referansı olmalıdır. Tüm görünüm olayları, işlenmek üzere sunum yapan kişiye iletilir ve neredeyse hiçbir zaman görünüm mantığı tarafından ele alınmaz (diğer görünümlerin oluşturulması dahil).

Kullanım örneği: Windows Formları.

Model-Görünüm-Görünüm Modeli


Bu yaklaşım, görünüm öğelerini Görünüm modelinin özellikleri ve olaylarıyla ilişkilendirmenize olanak tanır. Bu örüntünün her katmanının diğer katmanın varlığından habersiz olduğu söylenebilir.

Görünüm Modelinin Özellikleri:

  • Sunum ile iki yönlü iletişim;
  • Bir görünüm modeli, bir görünümün bir soyutlamasıdır. Genellikle Görünümün özelliklerinin Görünüm/Model özellikleriyle aynı olduğu anlamına gelir.
  • Görünüm modelinin görünüm arayüzüne (IView) referansı yoktur. Veri bağlama mekanizması (Bağlamalar) kullanıldığından, Görünüm modelinin durumunun değiştirilmesi görünümü otomatik olarak değiştirir ve bunun tersi de geçerlidir.
  • Görünüm Modelinin bir örneği, bir ekranla ilişkilendirilir.

Uygulama:
Bu kalıbı kullanırken, görünüm ilgili arabirimi (IView) uygulamaz.
Görünümün, bu durumda Görünüm modeli olan veri kaynağına (DataContex) bir bağlantısı olmalıdır. Görünüm öğeleri, Görünüm modelinin ilgili özelliklerine ve olaylarına bağlıdır (Bağlanır).
Buna karşılık, Görünüm modeli, görünüm öğelerini otomatik olarak güncellemek için kullanılan özel bir arabirim uygular. WPF'de böyle bir arabirime örnek olarak INotifyPropertyChanged verilebilir.

Kullanım örneği: WPF

Model-Görünüm-Denetleyici

Bu kalıbın ana fikri, hem denetleyicinin hem de görünümün modele bağlı olduğu, ancak modelin hiçbir şekilde bu iki bileşene bağlı olmadığıdır.

Denetleyici Özellikleri

  • Denetleyici, o anda hangi görünümün görüntüleneceğini belirler;
  • Olayları görüntüle, yalnızca denetleyiciyi etkileyebilir.Denetleyici, modeli etkileyebilir ve farklı bir görünüm tanımlayabilir.
  • Sadece bir kontrolör için birden fazla görünüme sahip olmak mümkündür;

Uygulama:
Kontrolör olaya dışarıdan müdahale eder ve içine gömülü olan mantığa uygun olarak bu olaya uygun metodu çağırarak Modeli değiştirerek tepki verir. Değişiklikten sonra Model, değiştirdiği olayı kullanır ve bu olaya abone olan tüm Görünüm olayları, onu aldıktan sonra, güncellenmiş veriler için Model'e döner ve ardından görüntülenirler.

Kullanım örneği: MVC ASP.NET

Özet
MVVM ve MVP modellerinin uygulanması, ilk bakışta oldukça basit ve benzer görünüyor. Ancak, MVVM için bir görünümün Görünüm modeline bağlanması otomatik olarak gerçekleştirilir ve MVP için programlanması gerekir.
MVC, görünümü yönetmek için daha fazla seçeneğe sahip görünüyor.
Bir desen seçmek için genel kurallar
OGVM
  • Özel görünüm arabirimlerini tanıtmaya gerek kalmadan veri bağlamanın mümkün olduğu bir durumda kullanılır (yani, IView uygulamaya gerek yoktur);
  • Yaygın bir örnek, WPF teknolojisidir.
MVP
  • Veri bağlamanın mümkün olmadığı bir durumda kullanılır (Binding'i kullanamazsınız);
  • Yaygın bir örnek, Windows Forms kullanmak olabilir.
MVC
  • Görünüm ile uygulamanın diğer bölümleri arasında iletişimin mümkün olmadığı (ve MVVM veya MVP kullanamadığınız) bir durumda kullanılır;
  • Yaygın bir kullanım örneği ASP.NET MVC'dir.
Çözüm
Sonuç olarak, bu makalenin yazarı yalnızca tek bir kalıba sıkı sıkıya bağlı kalmanın her zaman en iyi seçim olmadığını belirtmek ister. Örneğin, denetimlerin Bindings özelliği aracılığıyla Windows Forms kullanarak uygulamalar geliştirmek için MVVM kullanmak istediğinizi düşünün. Amacınız sunumu iş mantığından ve onları birbirine bağlayan mantıktan ayırmaktır. Uygulama kolayca test edilebilir, bakımı yapılabilir ve analistler için anlaşılabilir olmalıdır (sonuçta, “sabit disk performansı neyle ölçülür?” sorusunun yalnızca bir doğru cevabı vardır - Joule cinsinden (soyut bir Model -> Görünümler örneği) ).

Vakit ayırdığınız için çok teşekkür ederim, iyi okumalar!

desende " Model - Görünüm - Denetleyici" Bir model, uygulama verilerini ve bununla ilişkili iş mantığını temsil eder. Bir model, tek bir nesneyle veya ilgili nesnelerin karmaşık bir grafiğiyle temsil edilebilir. Bir platform uygulamasında Java EE veriler, genellikle bir EJB modülünde konuşlandırılan etki alanı nesnelerinde kapsüllenir. Veriler, veri aktarım nesnelerinde (DTO'lar) veri tabanına ve veri tabanından aktarılır ve veri erişim nesneleri (DAO'lar) kullanılarak erişilir.

Görünüm, modelde bulunan verilerin görsel bir temsilidir.Modelin bir alt kümesi ayrı bir görünümde bulunur, bu nedenle görünüm, modelin verileri için bir filtre görevi görür. Kullanıcı, görünümün sunduğu görselleştirme aracılığıyla model verileriyle etkileşime girer ve iş mantığına erişir, bu da model verileri üzerinde hareket eder.

Denetleyici, görünümü modelle ilişkilendirir ve uygulama verilerinin akışını yönetir. Kullanıcının girdisine yanıt olarak ve yürütülen iş mantığına göre hangi görünümün kullanıcıya sunulacağını seçer. Kontrolör, görünümden bir mesaj alır ve bunu modele iletir. Model sırayla bir yanıt hazırlar ve ero'yu, görünümün seçildiği ve kullanıcıya gönderildiği kontrolöre geri gönderir.

MVC Kalıbı mantıksal olarak katmanlı mimarinin istemci ve orta katmanını kapsar. Java ortamında, EE modeli, tipik olarak bir EJB modülü olarak iş katmanında bulunur.

Denetleyici ve görünüm, web katmanında bulunur. Görünüm büyük olasılıkla oluşturulacak JavaSunucu Yüzleri(JSF) veya Java Sunucusu Sayfaları(JSP) İfade Dili (EL) kullanarak. Denetleyici genellikle kullanıcıdan HTTP isteklerini alan bir sunucu uygulamasıdır.

MVC genellikle "Komut" (veya "Eylem"), "Strateji", "Birleştirici" ve " " gibi diğer kalıplarla birleştirilir.

Bu modelden ilk olarak, İnternet'in modern biçiminde yaratılmasından önce, o zamanlar bir Xeror SmallTalk programcısı olan Trygve Reenskaug tarafından Aralık 1979'da yayınlanan bir makalede bahsedilmiştir.

Ve bu kalıbın MVC öğeleri 35 yılı aşkın bir süre önce tanımlanmış olsa da, web uygulamalarında modern kullanımları için şaşırtıcı derecede doğrudurlar.

Aşağıdaki şekil, bir denetleyiciye istekte bulunan bir kullanıcıyı göstermektedir. Denetleyici, modeli güncelleyerek ve daha sonra kullanıcıya gönderilen yeni bir görünüm oluşturarak isteği işler.

MVC model diyagramı

MVC Kalıbıçok farklı şekillerde bulunur. En ünlü ikisine genellikle denir i yaz ve tip II.

MVC desen türleri:

  • MVC tipi I. Bu tür, görünüm ve denetleyicinin, görünüm denetleyicisi adı verilen tek bir varlık olarak bulunduğu sayfa yönelimli bir yaklaşımdır. Bu yaklaşımla, denetleyici mantığı JSF gibi bir görünümde uygulanır. HTTP istek özniteliklerini ve parametrelerini getirme, iş mantığını çağırma ve bir HTTP oturumunu yönetme dahil olmak üzere denetleyici tarafından gerçekleştirilen tüm görevler, komut dosyaları ve etiket kitaplıkları kullanılarak görünümde yerleşiktir. Tip I, sunum oluşturmayı uygulama tarafından gerçekleştirilen eylemler dizisiyle güçlü bir şekilde birleştirir ve böylece bakımı zorlaştırır.
  • MVC tip II. Tip I'deki sürdürülebilirlik sorunları, tip II'de, denetleyici mantığını görünümden sunucu uygulamasına taşıyarak ve veri işlemeyi görünüme bırakarak aşılır.

Tip I ve tip II arasındaki temel fark, kontrolör mantığının bulunduğu yerdir: tip I'de görünümde, tip II'de sunucu uygulamasındadır.

gibi birçok çerçeve Yay MVC'si, dikmeler, kaseler ve küçük kapı, Tip II MVC modelinin kendi sürümlerini uygular. Örneğin, Yay MVC'si HTTP istekleriyle etkileşime giren ve denetleyiciye temsilci atama gerçekleştiren bir gönderici sunucu uygulaması kavramını içerir ve bir görünüm (ve görünüm çözümleyicisi) ve işleyicileri içerir.

Aşağıdaki şekil, Spring'deki MVC modelinin bir uygulama diyagramını göstermektedir.

Yay MVC Örüntü Uygulama Şeması

Bence, projeye en iyi genişletilebilirliği sağlamak için sadece bir programcı değil, kesinlikle her geliştirici MVC'yi bilmelidir.

MVC sadece bir yazılım mimarisi değil aynı zamanda bir geliştirme konseptidir. Bu makalenin size MVC'nin tüm sırlarını anlatacağını söylemiyorum, ancak kesinlikle bir ilk anlayış elde edebilirsiniz. Ve sonra http://pogugli.com/?74600

MVC (Model-View-Controller) kavramı son yıllarda web programlama dünyasında çokça bahsedilmektedir. Web uygulamalarının gelişimi ile herhangi bir şekilde bağlantılı olan herkes, şu ya da bu şekilde bu kısaltmayla karşılaşmıştır. Bugün MVC konseptinin ne olduğunu ve neden popüler hale geldiğini anlayacağız.

Antik Tarih

MVC bir tasarım kalıbı değil, uygulamamızın yapılandırılma şeklini, bu yapıdaki her bir parçanın sorumluluklarını ve etkileşimini açıklayan bir tasarım kalıbıdır.

İlk olarak 1979'da tabi ki farklı bir ortam için tanımlanmıştır. O zaman bir web uygulaması kavramı yoktu. Tim Berners Lee, World Wide Web'in (WWW) tohumlarını doksanların başında ekti ve dünyayı sonsuza dek değiştirdi. Bugün kullandığımız şablon, web geliştirme için orijinal şablonun bir uyarlamasıdır.

Bu çerçevenin web uygulamalarında çılgınca popülaritesi, çok popüler hale gelen iki geliştirme ortamına dahil edilmesi nedeniyle gelişti: Struts ve Ruby on Rails. Bu iki geliştirme ortamı, daha sonra oluşturulan yüzlerce üretim ortamının yollarını çizdi.

Web uygulamaları için MVC

MVC tasarım modelinin arkasındaki fikir çok basittir: Uygulamalarımızdaki farklı davranışların sorumluluğunu net bir şekilde ayırmamız gerekir:

Uygulama, her biri farklı görevlerden sorumlu olan üç ana bileşene ayrılmıştır. Bir örnekle bileşenleri ayrıntılı olarak inceleyelim.

Denetleyici

Denetleyici, kullanıcı isteklerini işler (kullanıcı çeşitli eylemleri gerçekleştirmek için arayüz öğelerini tıkladığında HTTP GET veya POST istekleri olarak alınır). Ana işlevi, kullanıcı tarafından belirlenen eylemleri gerçekleştirmek için gerekli kaynakları ve nesneleri aramak ve koordine etmektir. Tipik olarak, denetleyici görev için uygun modeli çağırır ve uygun görünümü seçer.

modeli

Model, uygulamanın yönetim konseptini temsil eden verilerle çalışmak için kullanılan veriler ve kurallardır. Herhangi bir uygulamada, tüm yapı belirli bir şekilde işlenen veriler olarak modellenir. Bir uygulama için kullanıcı nedir - bir mesaj mı yoksa bir kitap mı? Yalnızca kurallara uygun olarak işlenmesi gereken veriler (tarih gelecekte olamaz, e-posta belirli bir formatta olmalıdır, ad X karakterden uzun olamaz vb.).

Model, denetleyiciye kullanıcının istediği verilerin (mesaj, kitap sayfası, fotoğraf albümü vb.) bir temsilini verir. Veri modeli, kullanıcıya nasıl sunmak istersek yapalım aynı olacaktır. Bu nedenle, verileri görüntülemek için mevcut herhangi bir görünümü seçiyoruz.

Model, uygulama mantığımızın en önemli kısmını, uğraştığımız sorunu çözen mantığı (forum, mağaza, banka vb.) içermektedir. Denetleyici, çoğunlukla uygulamanın kendisi için organizasyonel mantık içerir (temizlik gibi).

görüş

Bir görünüm, bir modelden alınan verileri sunmanın farklı yollarını sağlar. Verilerle dolu bir şablon olabilir. Birkaç farklı görünüm olabilir ve kontrolör mevcut duruma en uygun olanı seçer.

Bir web uygulaması genellikle bir dizi denetleyici, model ve görünümden oluşur. Bir denetleyici, tüm istekleri alan ve duruma bağlı olarak eylemleri gerçekleştirmeleri için diğer denetleyicileri çağıran bir ana denetleyici olarak kurulabilir.

bir örnek alalım

Bir çevrimiçi kitapçı geliştirmemiz gerektiğini varsayalım. Kullanıcı aşağıdaki eylemleri gerçekleştirebilir: kitapları görüntüleme, kaydolma, satın alma, mevcut siparişe öğe ekleme, kitap oluşturma veya silme (yöneticiyse). Kullanıcı bir kategoriye tıkladığında ne olacağını görelim fantezi Mağazamızda bulunan kitapların isimlerini görmek için.

Kitaplarla ilgili tüm eylemleri (görüntüleme, düzenleme, oluşturma vb.) diyelim kitaplar_kontrolcü.php bizim örneğimizde. Ayrıca bir modele ihtiyacımız var, örneğin, kitap_modeli.php Mağaza öğesiyle ilişkili verileri ve mantığı işleyen bir. Son olarak, bir kitap listesi, bir düzenleme sayfası vb. gibi verileri temsil etmek için birkaç görünüme ihtiyacımız var.

Aşağıdaki şekil, bir kullanıcının ilgili kitapların listesini görüntüleme isteğinin nasıl ele alındığını gösterir. fantezi:

Denetleyici (books_controller.php), kullanıcının isteğini (bir HTTP GET veya POST isteği) alır. Talebi alan ve book_controller.php'yi çağıran index.php gibi bir merkezi controller kurabiliriz.

Kontrolör, isteği ve parametreleri kontrol eder ve ardından modeli (book_model.php) çağırır, soran konuyla ilgili mevcut kitapların bir listesi var fantezi.

Model, veri tabanından (veya bilgi depolayan başka bir kaynaktan) verileri alır, filtreleri ve gerekli mantığı uygular ve ardından kitap listesini temsil eden verileri döndürür.

Denetleyici, verileri kullanıcıya sunmak için uygun görünümü kullanır. Talep bir cep telefonundan geliyorsa, mobil görünüm kullanılır; kullanıcı belirli bir arayüz tasarımı kullanıyorsa, uygun görünüm seçilir ve bu şekilde devam eder.

Faydaları nelerdir?

MVC konseptini kullanmaktan elde ettiğimiz en belirgin fayda, sunum (kullanıcı arayüzü) mantığı ile uygulama mantığının net bir şekilde ayrılmasıdır.

Farklı türde cihazlar kullanan farklı kullanıcı türleri için destek, bugünlerde yaygın bir sorundur. Talep bir bilgisayardan veya cep telefonundan geliyorsa, sağlanan arayüz farklı olmalıdır. Model aynı verileri döndürür, tek fark denetleyicinin verileri görüntülemek için farklı görünümler seçmesidir.

Görünümleri uygulama mantığından ayırmaya ek olarak, MVC konsepti büyük uygulamaların karmaşıklığını büyük ölçüde azaltır. Kod çok daha yapılandırılmıştır, bu da çözümlerin bakımını, test edilmesini ve yeniden kullanılmasını kolaylaştırır.

Neden bir çalışma tezgahı kullanmalısınız?

Bir çalışma tezgahı kullandığınızda, temel MVC yapısı zaten yerindedir ve tek yapmanız gereken dosyalarınızı MVC modeline uyacak şekilde uygun dizinlere yerleştirerek yapıyı genişletmektir. Ayrıca, önceden yazılmış ve iyi test edilmiş bir dizi fonksiyona sahip olacaksınız.

Bir MVC tezgahı örneği olarak cakePHP'yi alalım. Kurulumdan sonra üç ana dizine sahip olacaksınız:

  • Kek/
  • satıcılar/

Dosya app, dosyalarınızı koyduğunuz yerdir. Bu, uygulamanın kendi bölümünü geliştirme yeridir.

klasörde cake, cakePHP dosyalarını barındırır (masaüstü işlevselliği).

Dosya satıcılar, üçüncü taraf PHP kitaplıklarını depolamak için kullanılır.

Çalışma alanınız (uygulama dizini) aşağıdaki yapıya sahiptir:

  • uygulama/
    • yapılandırma/
    • kontrolörler/
    • yerel/
    • modeller/
    • eklentiler/
    • testler/
    • satıcılar/
    • Görüntüleme/
    • web kökü/

Denetleyicilerinizi denetleyiciler dizinine, modelleri modeller dizinine ve görünümleri görünümler dizinine koymanız gerekir!

Tezgahı kullanmaya başladığınız anda, uygulamanızın oluşturulması veya değiştirilmesi gereken hemen hemen her parçasının nerede olduğu hemen anlaşılır. Bu organizasyon başlı başına bir uygulama geliştirme ve sürdürme sürecini büyük ölçüde basitleştirir.

Örneğimiz için çalışma alanını kullanma

Bu ders cakePHP ile bir uygulamanın nasıl oluşturulacağını göstermeyi amaçlamadığından, MVC workbench'i kullanmanın faydaları hakkında yorumlarla birlikte sadece model, kontrolör ve görünüm için kodu göstereceğiz. Kod kasıtlı olarak basitleştirilmiştir ve gerçek bir uygulamada kullanım için uygun değildir.

Unutmayın, bir kitapçıya ve konuyla ilgili kitapların tam listesini görmek isteyen meraklı bir kullanıcıya bakıyorduk. fantezi. Kontrolör, kullanıcının talebini aldı ve gerekli eylemleri koordine etti.

Bu nedenle, kullanıcı düğmeye basar tıklamaz tarayıcı verilen url'yi ister:

1 www.ourstore.com/books/list/fantasy

CakePHP şablon URL biçimlendirme /denetleyici/eylem/param1/param2, nerede eylem denetleyici tarafından çağrılan bir fonksiyondur. Eski klasik formda, url şöyle görünecektir:

1 www.ourstore.com/books_controller.php?action=list&category=fantezi

Denetleyici

CakePHP çalışma alanında denetleyicimiz şöyle görünecek:

1
class BooksController, AppController'ı genişletir(

fonksiyon listesi($kategori) (

$this ->set("books" , $this ->Kitap->findAllByCategory($category));

}

fonksiyon ekleme() ( ... ... )

fonksiyon silme () ( ... ... )

... ... } ?>

Basit, değil mi? Bu denetleyici olarak kaydedilecek kitaplar_kontrolcü.php ve yerleştirilmiş /app/kontrolörler. Örneğimiz için eylemleri gerçekleştiren işlevlerin bir listesini ve kitapla ilgili işlemleri gerçekleştirmek için diğer işlevleri (yeni bir kitap ekleme, bir kitap silme vb.) içerir.

Çalışma ortamı bize birçok hazır çözüm sunuyor ve bize sadece bir kitap listesi oluşturmamız gerekiyor. Denetleyicinin temel işlevlerinin önceden tanımlandığı bir temel sınıf vardır, bu nedenle bu sınıfın özelliklerini ve işlevlerini devralmanız gerekir ( Uygulama Denetleyicisi mirasçı mı kontrolör).

Eylem listesinde yapmanız gereken tek şey, verileri almak için modeli çağırmak ve ardından kullanıcıya sunmak için görünümü seçmek. İşte nasıl yapıldığı.

bu->Kitap bizim modelimiz ve kodun bir parçası:

1 $bu ->Kitap->findAllByCategory($kategori)

modele seçilen konuyla ilgili kitapların bir listesini döndürmesini söyler (modele daha sonra bakacağız).

Yöntem AyarlamakÇizgide:

1 $this ->set("books" , $this ->Kitap->findAllByCategory($category));

Denetleyici, verileri görünüme geçirir. Değişken kitabın model tarafından döndürülen verileri alır ve görünüm için kullanılabilir hale getirir.

Şimdi yapılacak tek şey görünümü görüntülemek, ancak bu işlev, varsayılan görünümü kullanırsak cakePHP'de otomatik olarak yapılır. Farklı bir görünüm kullanmak istiyorsak, yöntemi açıkça çağırmalıyız. render.

modeli

Model daha da basit:

1
sınıf Kitap, AppModel'i genişletir(

}

?>

Neden boş? Gerekli işlevselliği sağlayan bir temel sınıftan miras aldığı için ve workbench'in diğer tüm görevleri otomatik olarak gerçekleştirmesi için CakePHP'nin adlandırma kuralını kullanmamız gerekiyor. Örneğin, cakePHP, bu modelin şu anda kullanıldığını adından bilir. KitaplarDenetleyici ve kitaplar adlı bir veritabanı tablosuna erişimi olduğunu.

Bu tanım ile sadece veri tabanındaki verileri okuyabilen, silebilen veya depolayabilen bir modelimiz olacak.

Kodu farklı kaydet kitap.php klasörde /uygulama/modeller.

görüş

Şimdi tek yapmamız gereken eylem listesi için bir görünüm (en az bir) oluşturmak. Görünüm, HTML koduna ve model tarafından sağlanan kitap dizisinde dolaşmak için birkaç (mümkün olduğunca az) PHP kodu satırına sahip olacaktır.

1














İsim Yazar Fiyat

Gördüğünüz gibi, görünüm tam teşekküllü bir sayfa değil, yalnızca bir HTML parçası (bu durumda bir tablo) oluşturur. Çünkü CakePHP, bir sayfa şablonu tanımlamanın başka bir yolunu sağlar ve görünüm bu şablona eklenir. Workbench ayrıca bize bir HTML sayfasının bölümlerini (formlar, bağlantılar, Ajax veya JavaScript ekleme) oluştururken ortak görevleri gerçekleştirmemiz için bazı yardımcı nesneler sağlar.

Görünümü farklı kaydet liste.ctp(liste eylem adıdır ve ctp CakePHP şablonu anlamına gelir) klasörde /uygulama/görüntülemeler/kitaplar(çünkü bu bir denetleyici eylemi için bir görünümdür).

CakePHP tezgahı kullanılarak üç bileşenin tamamı bu şekilde yürütülür!

Model-View-Controller (MVC) modeli, karmaşık GUI'lere veya davranışlara sahip uygulamalar oluştururken son derece kullanışlıdır. Ancak daha basit durumlar için de uygundur. Bu yazıda, bu model etrafında tasarlanmış bir mayın tarama gemisi oyunu oluşturacağız. Geliştirme dili olarak Python seçilmiştir, ancak bunun özel bir önemi yoktur. Kalıplar belirli bir programlama diline bağlı değildir ve ortaya çıkan uygulamayı başka bir platforma kolayca aktarabilirsiniz.

reklam

Kısaca MVC modeli hakkında

Adından da anlaşılacağı gibi, MVC modelinin 3 bileşeni vardır: Model, Görünüm ve Denetleyici. Bileşenlerin her biri rolünü yerine getirir ve değiştirilebilir. Bu, bileşenlerin birbirine yalnızca arkasında herhangi bir uygulamanın yatabileceği bazı açık arabirimlerle bağlı olduğu anlamına gelir. Bu yaklaşım, gerekli çalışma mantığını veya uygulamanın görünümünü sağlayarak çeşitli bileşenleri değiştirmenize ve birleştirmenize olanak tanır. Her bileşenin gerçekleştirdiği işlevlere bakalım.

modeli

Programın iç mantığından sorumludur. Burada veri depolamanın yollarını ve ayrıca bilgi işleme kuralları ve algoritmalarını gizleyebiliriz.

Örneğin, bir uygulama için birkaç model oluşturabiliriz. Biri hata ayıklıyor, diğeri çalışıyor. Birincisi verilerini bellekte veya bir dosyada saklayabilir ve ikincisi zaten veritabanını kullanır. Aslında, bu sadece bir Strateji kalıbıdır.

Verim

Model verilerinin görüntülenmesinden sorumludur. Bu seviyede, yalnızca Model ile kullanıcı etkileşimi için bir arayüz sağlıyoruz. Bu bileşeni tanıtmanın amacı, birkaç Modele dayalı olarak farklı veri depolama yolları sağlama durumuyla aynıdır.

Örneğin, geliştirmenin ilk aşamalarında uygulamamız için basit bir konsol görünümü oluşturabilir ve ancak o zaman güzel tasarlanmış bir GUI ekleyebiliriz. Ayrıca, her iki arabirim türünü de kaydetmek mümkündür.

Ayrıca, View'in sorumluluğunun sadece Modelin durumunu zamanında göstermek olduğu unutulmamalıdır. Denetleyici, şimdi bahsedeceğimiz kullanıcı eylemlerini işlemekten sorumludur.

Denetleyici

Model ile Görünüm ile etkileşimden kaynaklanan kullanıcı eylemleri arasında bir bağlantı sağlar. Model ve Görünüm durumları güncellendiğinde koordinatlar. Bir durumdan diğerine uygulama geçişleriyle ilgili kararların çoğunu verir.

Aslında, kullanıcının Görünümde gerçekleştirebileceği her eylem için Denetleyicide bir işleyici tanımlanmalıdır. Bu işleyici, model üzerinde uygun manipülasyonları gerçekleştirecek ve gerekirse, değişikliklerin varlığı hakkında Görünümü bilgilendirecektir.

reklam

Mayın Tarlası Oyun Özellikleri

Yeter teori. Şimdi uygulamaya geçelim. MVC modelini göstermek için basit bir oyun yazacağız: Mayın Tarlası. Oyunun kuralları oldukça basit:

  1. Oyun alanı hücrelerden oluşan dikdörtgen bir alandır. Mayınlar bazı hücrelere rastgele yerleştirilir, ancak oyuncunun onlardan haberi yoktur;
  2. Oyuncu, sol veya sağ fare düğmeleriyle oyun alanının herhangi bir hücresine tıklayabilir;
  3. Farenin sol tuşuna tıklamak hücrenin açılmasına neden olur. Bu durumda, hücrede bir mayın varsa, oyun bir kayıpla sona erer. Komşu hücrelerde mayın varsa, açık hücrenin yanında, açık hücrede etrafındaki mayın sayısını gösteren bir sayaç görüntülenecektir. Açık bir hücrenin etrafında mayın yoksa, her bitişik hücre aynı prensibe göre açılacaktır. Yani hücreler ya oyun alanının sınırına gelene ya da zaten açık olan hücrelere ulaşana ya da yanlarında bir mayın bulunana kadar açılacaktır;
  4. Farenin sağ düğmesine tıklamak, hücreler üzerinde işaretler yapmanızı sağlar. Kapalı bir hücreye tıklamak, durumunu kilitleyen ve yanlışlıkla açılmasını önleyen bir bayrakla işaretler. Bayrakla işaretlenmiş bir hücreye tıklamak, bayrağını soru işaretine dönüştürür. Bu durumda hücre artık bloke değildir ve farenin sol tuşu ile açılabilir. Soru işareti olan bir hücreye tıklamak, işaretlenmemiş kapalı durumunu döndürür;
  5. Zafer, mayınlı olanlar hariç, oyun alanındaki tüm hücrelerin açık olduğu oyunun durumuna göre belirlenir.

Aldığımız şeyin bir örneği aşağıda gösterilmiştir:

Mayın Tarlası UML Diyagramları

Kod yazmaya geçmeden önce, uygulamanın mimarisini önceden düşünmek iyi olur. Uygulama diline bağlı olmamalıdır, bu nedenle UML, amaçlarımız için en uygun olanıdır.

Oyun Hücresi Durum Şeması

Oyun alanındaki herhangi bir hücre 4 durumdan birinde olabilir:

  1. Hücre kapalı;
  2. Kafes açık;
  3. Hücre işaretlenir;
  4. Hücre bir soru işareti ile işaretlenmiştir.

Burada sadece Görünüm ile ilgili durumları tanımladık. Mayınlar oyun sırasında gösterilmediğinden, temel sette de ilgili durum sağlanmaz. UML Durum Diyagramlarını kullanarak bir hücre durumundan diğerine olası geçişleri tanımlayalım:

Mayın Tarlası Sınıf Şeması

Uygulamamızı MVC modeline dayalı olarak oluşturmaya karar verdiğimiz için, üç ana sınıfımız olacak: MinesweeperModel , MinesweeperView ve MinesweeperController , ayrıca hücrenin durumunu depolamak için bir yardımcı sınıf MinesweeperCell. Sınıf diyagramlarını düşünün:

Mimarinin organizasyonu oldukça basittir. Burada görevleri MVC modelinin ilkelerine uygun olarak her sınıfa basitçe dağıttık:

  1. Hiyerarşinin en altında MinesweeperCell oyun hücresi sınıfı bulunur. Oyun alanının satır satırı ve sütun sütunu tarafından belirlenen hücrenin konumunu saklar; önceki alt bölümde tanımladığımız durumlardan biri; hücrede (mayınlı) mayın varlığı ve komşu hücrelerde mayın sayacı sayacı hakkında bilgi. Ek olarak, iki yöntemi vardır: sağ tıklama işareti durumları arasında geçiş yapmak için nextMark() ve sol tıklama olayını işleyen open();
  2. Mayın TarlasıModel Model sınıfı biraz daha yüksektir. Mayın Tarlası Hücresi oyun hücresi kabıdır. İlk startGame() yöntemi, oyun alanını oyunun başlaması için hazırlar. isWin() yöntemi, oyun alanında bir kazanma durumu olup olmadığını kontrol eder ve oyuncu kazanmışsa true döndürür, aksi takdirde false döndürür. Benzer bir isGameOver() yöntemi, kaybı kontrol etmek için tasarlanmıştır. openCell() ve nextCellMark() yöntemleri, eylemleri oyun alanındaki ilgili hücrelere devreder ve getCell() yöntemi istenen oyun hücresini döndürür;
  3. MinesweeperView View sınıfı aşağıdaki yöntemleri içerir: syncWithModel() - Modeldeki oyun alanının mevcut durumunu görüntülemek için Görünümün yeniden çizilmesini sağlar; getGameSettings() - kullanıcı tarafından belirlenen oyun ayarlarını döndürür; createBoard() - Model verilerine dayalı bir oyun alanı yaratır; showWinMessage() ve showGameOverMessage() sırasıyla kazanma ve kaybetme mesajlarını görüntüler;
  4. Ve son olarak MinesweeperController Controller sınıfı. Oyuncunun her olası eylemi için yalnızca üç yöntem tanımlar: StartNewGame(), Görünüm arayüzündeki "Yeni Oyun" düğmesine tıklamaktan sorumludur; onLeftClick() ve onRightClick(), sırasıyla sol ve sağ fare düğmeleriyle oyun hücrelerine yapılan tıklamaları yönetir.

Mayın Tarlası oyununun Python'da uygulanması

Projemizi uygulamaya başlama zamanı. Geliştirme dili olarak Python'u seçeceğiz. Ardından tkinter modülünü temel alarak View sınıfını yazacağız.

Ama Modelle başlayalım.

MinsweeperModel

Modelin Python'da uygulanması şöyle görünür:

MIN_ROW_COUNT = 5 MAX_ROW_COUNT = 30 MIN_COLUMN_COUNT = 5 MAX_COLUMN_COUNT = 30 MIN_MINE_COUNT = 1 MAX_MINE_COUNT = 800 sınıf Mayın TarlasıHücresi: # Olası oyun hücresi durumları: # kapalı - kapalı # açık - açıldı # işaretli - işaretli # self __init( , satır, .row = satır self.column = sütun self.state = "kapalı" self.mined = False self.counter = 0 markSequence = [ "kapalı", "işaretli", "sorgulandı" ] def nextMark (self): if self. self.markSequence'da durum: stateIndex = self.markSequence.index(self.state) self.state = self.markSequence[ (stateIndex + 1) % len(self.markSequence) ] def open(self ): if self.state ! = "flagged": self.state = "açık" sınıf Mayın TarlasıModel: def __init__(self): self.startGame() def startGame(self, rowCount = 15, columnCount = 15, mineCount = 15) : eğer rowCount in range(MIN_ROW_COUNT) , MAX_ROW_COUNT + 1): self.rowCount = rowCount, eğer columnCount aralık içindeyse(MIN_COLUMN_COUNT, MAX_COLUMN_COUNT + 1): self.columnCount = eğer mineCount ise columnCount< self.rowCount * self.columnCount: if mineCount in range(MIN_MINE_COUNT, MAX_MINE_COUNT + 1): self.mineCount = mineCount else: self.mineCount = self.rowCount * self.columnCount - 1 self.firstStep = True self.gameOver = False self.cellsTable = for row in range(self.rowCount): cellsRow = for column in range(self.columnCount): cellsRow.append(MinesweeperCell(row, column)) self.cellsTable.append(cellsRow) def getCell(self, row, column): if row < 0 or column < 0 or self.rowCount <= row or self.columnCount <= column: return None return self.cellsTable[ row ][ column ] def isWin(self): for row in range(self.rowCount): for column in range(self.columnCount): cell = self.cellsTable[ row ][ column ] if not cell.mined and (cell.state != "opened" and cell.state != "flagged"): return False return True def isGameOver(self): return self.gameOver def openCell(self, row, column): cell = self.getCell(row, column) if not cell: return cell.open() if cell.mined: self.gameOver = True return if self.firstStep: self.firstStep = False self.generateMines() cell.counter = self.countMinesAroundCell(row, column) if cell.counter == 0: neighbours = self.getCellNeighbours(row, column) for n in neighbours: if n.state == "closed": self.openCell(n.row, n.column) def nextCellMark(self, row, column): cell = self.getCell(row, column) if cell: cell.nextMark() def generateMines(self): for i in range(self.mineCount): while True: row = random.randint(0, self.rowCount - 1) column = random.randint(0, self.columnCount - 1) cell = self.getCell(row, column) if not cell.state == "opened" and not cell.mined: cell.mined = True break def countMinesAroundCell(self, row, column): neighbours = self.getCellNeighbours(row, column) return sum(1 for n in neighbours if n.mined) def getCellNeighbours(self, row, column): neighbours = for r in range(row - 1, row + 2): neighbours.append(self.getCell(r, column - 1)) if r != row: neighbours.append(self.getCell(r, column)) neighbours.append(self.getCell(r, column + 1)) return filter(lambda n: n is not None, neighbours)

En üstte, izin verilen oyun ayarları aralığını tanımlıyoruz:

MIN_ROW_COUNT = 5 MAX_ROW_COUNT = 30 MIN_COLUMN_COUNT = 5 MAX_COLUMN_COUNT = 30 MIN_MINE_COUNT = 1 MAX_MINE_COUNT = 800

Genel olarak, bu ayarlar Modelin bir parçası da yapılabilir. Ancak sahanın büyüklüğü ve mayın sayısı oldukça statik bir bilgidir ve sık sık değişmesi pek olası değildir.

Daha sonra MinesweeperCell oyun hücresi sınıfını tanımladık. Oldukça basit olduğu ortaya çıktı. Sınıf yapıcısında, hücre alanları varsayılan değerlerle başlatılır. Daha sonra, döngüsel durum geçişlerinin uygulanmasını basitleştirmek için markSequence yardımcı listesini kullanırız. Hücre, bu listede yer almayan "açık" durumdaysa, nextMark() yönteminde hiçbir şey olmaz, aksi takdirde hücre bir sonraki duruma girer ve son "sorgulanan" durumundan " "kapalı" "ilk durumuna atlar. open() yönteminde hücrenin durumunu kontrol ederiz ve eğer "flagged" değerine eşit değilse hücre "opened" durumuna geçer.

Aşağıda, Mayın TarlasıModel Model sınıfının tanımı yer almaktadır. startGame() yöntemi, kendisine iletilen rowCount , columnCount ve mineCount parametrelerine göre oyun alanını düzenler. Parametrelerin her biri için izin verilen değerler aralığında olup olmadığı kontrol edilir. Geçilen değer aralık dışındaysa, oyun alanı parametresinin değeri değişmez. Mayın sayısı için ek bir kontrol sağlandığına dikkat edilmelidir. Aktarılan mayın sayısı alanın boyutunu aşarsa, bunu hücre sayısıyla sınırlandırırız. Tabii ki, böyle bir oyun pek mantıklı gelmese ve tek adımda tamamlanacak olsa da, böyle bir durum için bir tür kendi kuralınızı oluşturabilirsiniz.

Oyun alanı, cellTable değişkenindeki hücre listelerinin bir listesi olarak saklanır. Ayrıca, startGame() yönteminde hücreler için yalnızca konum değerinin ayarlandığını ancak mayınların henüz yerleştirilmediğini lütfen unutmayın. Bunun yerine, firstStep değişkeni True değeriyle tanımlanır. Bu, ilk hamlede şans unsurunu ortadan kaldırmak ve ani bir kaybı önlemek için gereklidir. Mayınlar, kalan hücrelere ilk hamleden sonra yerleştirilecek.

getCell() yöntemi, oyun alanının hücresini satır satır ve sütun sütununa göre döndürür. Satır veya sütun değeri geçersizse, Yok döndürülür.

isWin() yöntemi, oyun alanının kalan tüm açılmamış hücrelerinin madenciliği yapılırsa True döndürür, yani zafer durumunda, aksi takdirde False döndürür. isGameOver() yöntemi basitçe gameOver sınıf özniteliğinin değerini döndürür.

openCell() yönteminde, open() çağrısı, oyun alanında yöntem parametrelerinde belirtilen konumda bulunan oyun hücresi nesnesine devredilir. Açık hücre mayınlıysa, gameOver değerini True olarak ayarlıyoruz ve yöntemden çıkıyoruz. Oyun henüz bitmediyse, firstStep değerini kontrol ederek ilk hamle olup olmadığına bakarız. Eğer hareket gerçekten ilkse, o zaman mayınlar, biraz sonra bahsedeceğimiz createMines() helper metodu kullanılarak oyun sahasına yerleştirilecektir. Ardından, mayınlı komşu hücrelerin sayısını sayarız ve işlenen hücre için sayaç özniteliğinin karşılık gelen değerini belirleriz. Sayaç sıfırsa, getCellNeighbors() yöntemini kullanarak komşu hücrelerin bir listesini isteriz ve tüm kapalı "komşular" için, yani "kapalı" durumundaki hücreler için yinelemeli olarak openCell() yöntemini çağırırız.

nextCellMark() yöntemi, verilen konumdaki hücre için çağrıyı nextMark() yöntemine devreder.

Mayınlar, createMines() yöntemine yerleştirilir. Burada sadece oyun alanında rastgele bir pozisyon seçiyoruz ve bu pozisyondaki hücrenin açık olmadığını ve daha önce mayınlı olmadığını kontrol ediyoruz. Her iki koşul da karşılanırsa, mayınlı özniteliğin değerini True olarak ayarlarız, aksi takdirde başka bir boş hücre aramaya devam ederiz. Python'da random modülünü kullanmak için import random komutu ile açıkça import etmeniz gerektiğini unutmayın.

Oyun alanının belirli bir hücresinin etrafındaki mayın sayısını saymak için kullanılan countMinesAroundCell() yöntemi, tamamen getCellNeighbors() yöntemine dayalıdır. getCellNeighbors() yönteminde hücrenin "komşular" isteği de çok basit bir şekilde uygulanır. Bununla ilgili herhangi bir problem yaşayacağınızı düşünmüyorum.

Mayın TarlasıGörünüm

Şimdi sunuma geçelim. Python'daki MinesweeperView sınıf kodu aşağıda gösterilmiştir:

Sınıf Mayın TarlasıView(Frame): def __init__(self, model, controller, parent = None): Frame.__init__(self, parent) self.model = model self.controller = controller self.controller.setView(self) self.createBoard( ) panel = Çerçeve(self) panel.pack(yan = ALT, dolgu = X) Düğme(panel, metin = "Yeni Oyun", komut = self.controller.startNewGame).pack(yan = SAĞ) self.mineCount = StringVar (panel) self.mineCount.set(self.model.mineCount) Spinbox(panel, from_ = MIN_MINE_COUNT, to = MAX_MINE_COUNT, textvariable = self.mineCount, genişlik = 5).pack(yan = SAĞ) Etiket(panel, metin = " Dakika sayısı: ".pack(side = RIGHT) self.rowCount = StringVar(panel) self.rowCount.set(self.model.rowCount) Spinbox(panel, from_ = MIN_ROW_COUNT, to = MAX_ROW_COUNT, textvariable = self.rowCount , genişlik = 5).pack(yan = SAĞ) Label(panel, metin = " x ").pack(yan = SAĞ) self.columnCount = StringVar(panel) self.columnCount.set(self.model.columnCount) Spinbox (panel, from_ = MIN_COLUMN_COUN T, to = MAX_COLUMN_COUNT, textvariable = self.columnCount, width = 5).pack(side = RIGHT) Label(panel, text = "Field size: ").pack(side = RIGHT) def syncWithModel(self): for row in range(self.model.rowCount): range içindeki sütun için(self.model.columnCount): cell = self.model.getCell(satır, sütun) ise hücre: btn = self.buttonsTable[ satır ][ sütun ] ise self .model.isGameOver() ve cell.mined: btn.config(bg = "siyah", metin = "") eğer cell.state == "kapalı": btn.config(text = "") elif cell.state = = "açıldı": btn.config(kabartma = BATIK, metin = "") eğer cell.counter > 0: btn.config(text = cell.counter) elif cell.mined: btn.config(bg = "red") elif cell.state == "işaretli": btn.config(text = "P") elif cell.state == "sorgulanan": btn.config(text = "?") def blockCell(kendi, satır, sütun, blok = True): btn = self.buttonsTable[ satır ][ sütun ] btn değilse: dönüş if bloğu: btn.bind(" ", "break") başka: btn.unbind(" ") def getGameSettings(self): return self.rowCount.get(), self.columnCount.get(), self.mineCount.get() def createBoard(self): deneyin: self.board.pack_forget() self.board .destroy() self.rowCount.set(self.model.rowCount) self.columnCount.set(self.model.columnCount) self.mineCount.set(self.model.mineCount) hariç: pass self.board = Frame(self ) self.board.pack() self.buttonsTable = aralıktaki satır için(self.model.rowCount): line = Çerçeve(self.board) line.pack(yan = TOP) self.buttonsRow = aralıktaki sütun için(self) .model.columnCount): btn = Düğme(çizgi, genişlik = 2, yükseklik = 1, komut = lambda satır = satır, sütun = sütun: self.controller.onLeftClick(satır, sütun), padx = 0, pady = 0) btn.pack(yan = SOL) btn.bind(" ", lambda e, satır = satır, sütun = sütun: self.controller.onRightClick(satır, sütun)) self.buttonsRow.append(btn) self.buttonsTable.append(self.buttonsRow) def showWinMessage(self): showinfo( "Tebrikler!", "Kazandınız!") def showGameOverMessage(self): showinfo("Oyun Bitti!", "Kaybettiniz!")

Görünümümüz tkinter modülündeki Frame sınıfını temel alır, bu nedenle uygun import komutunu çalıştırmayı unutmayın: from tkinter import * . Sınıf yapıcısında Model ve Denetleyici iletilir. Oyun alanını hücrelerden düzenlemek için hemen createBoard() yöntemi çağrılır. Bu amaçla her zamanki düğmelerini kullanacağımızı şimdiden söyleyeceğim Button . Ardından, oyun seçeneklerini belirlemek için bir alt panel görevi görecek bir Çerçeve oluşturulur. Bu panelde, işleyicisi startNewGame() yöntemiyle Kontrolörümüz olan "Yeni Oyun" düğmesini ve ardından oyuncunun oyun alanının boyutunu ve mayın sayısını belirleyebilmesi için üç Spinbox sayacını sırayla yerleştiriyoruz. .

syncWithModel() yöntemi, her oyun hücresinde iki kez döngü yapar ve GUI'mizde onu temsil eden düğmenin görünümünü buna göre değiştirir. Basitlik adına, sembolleri görüntülemek için metin sembolleri kullandım, ancak metni harici grafik dosyalarından grafiğe dönüştürmek o kadar zor değil.

Ayrıca, açık hücreyi temsil etmek için SUNKEN düğme stilini kullandığımıza dikkat edin. Ve bir kayıp durumunda, ilgili düğmeleri siyah olarak göstererek oyun alanındaki tüm mayınların yerini açarız ve bir mayınlı son açık hücreye karşılık gelen düğme kırmızı ile vurgulanır:

Aşağıdaki blockCell() yöntemi bir yardımcı görevi görür ve denetleyicinin düğmeler için engelleme durumunu ayarlamasına olanak tanır. Bu, bir bayrakla işaretlenmiş oyun hücrelerinin yanlışlıkla açılmasını önlemek içindir ve boş bir fare sol tıklama işleyicisi ayarlanarak elde edilir.

getGameSettings() yöntemi, yalnızca alt panele yerleştirilen sayaçların oyun alanının boyutu ve mayın sayısı ile birlikte değerlerini döndürür.

Oyun alanı temsilinin oluşturulması, createBoard() yönteminde yapılır. Öncelikle eski oyun alanı var ise silmeye çalışıyoruz ve ayrıca mevcut Model konfigürasyonuna uygun olarak sayaçların değerlerini panelden ayarlamaya çalışıyoruz. Ardından, oyun alanını temsil etmek için board olarak adlandıracağımız yeni bir Çerçeve oluşturulur. Butonlar tablosunu, Modeldeki oyun hücreleriyle aynı prensibe göre çift döngü kullanarak oluşturuyoruz. Her düğmenin işleyicileri, sırasıyla sol ve sağ fare düğmelerine tıklamak için Denetleyicinin onLeftClick() ve onRightClick() yöntemlerine bağlıdır.

Son iki yöntem, showWinMessage() ve showGameOverMessage() , showinfo() işlevini kullanarak uygun mesajları içeren iletişim kutularını görüntülemeniz yeterlidir. Kullanmak için bir modülü daha içe aktarmanız gerekir: from tkinter.messagebox import * .

Mayın TarlasıDenetleyici

İşte Denetleyicinin uygulanmasına geliyoruz:

Mayın TarlasıDenetleyici Sınıfı: def __init__(self, model): self.model = model def setView(self, view): self.view = view def startNewGame(self): gameSettings = self.view.getGameSettings() deneyin: self.model. startGame(*map(int, gameSettings)) hariç: self.model.startGame(self.model.rowCount, self.model.columnCount, self.model.mineCount) self.view.createBoard() def onLeftClick(self, row, sütun): self.model.openCell(satır, sütun) self.view.syncWithModel() if self.model.isWin(): self.view.showWinMessage() self.startNewGame() elif self.model.isGameOver(): self.view.showGameOverMessage() self.startNewGame() def onRightClick(self, satır, sütun): self.model.nextCellMark(satır, sütun) self.view.blockCell(satır, sütun, self.model.getCell(satır, sütun).state == "işaretli") self.view.syncWithModel()

Bir Görünümü bir Denetleyiciye bağlamak için setView() yöntemini ekledik. Bunun nedeni, yapıcıya bir Görünüm iletmek istiyorsak, o Görünümün Denetleyici oluşturulmadan önce zaten var olması gerekmesidir. Ve sonra, ek bir bağlama yöntemine sahip böyle bir çözüm, Denetleyiciden, setController() yönteminin görüneceği Görünüm'e geçer.

Yeni Oyun düğmesi tıklama işleyici yöntemi startNewGame() önce Görünüm'e girilen oyun ayarlarını sorgular. Oyun parametreleri, bir int biçimine dönüştürmeye çalıştığımız 3'lü bir demet olarak döndürülür. Her şey yolunda giderse, oyun alanını oluşturmak için bu değerleri Model'in startGame() yöntemine iletiyoruz. Bir şeyler ters giderse, oyun alanını eski parametrelerle yeniden oluşturacağız. Son olarak, createBoard() yöntemini çağırarak Görünümde yeni bir pano görüntüsü oluşturmak için bir istek göndeririz.

onLeftClick() işleyicisi önce Model'e oyun hücresini oyuncunun seçtiği konumda açmasını söyler. Daha sonra Görünüme Modelin durumunun değiştiğini söyler ve her şeyi yeniden çizmeyi teklif eder. Ardından Model, zafer veya kayıp durumu için kontrol edilir. Bunlardan herhangi biri olursa, önce Görünüm'e uygun bildirimi göstermesi için bir istek gönderilir ve ardından yeni bir oyun başlatmak için startNewGame() işleyicisi çağrılır.

Sağ fare tıklaması, onRightClick() yönteminde işlenir. İlk satır, seçilen oyun hücresinin etiketi arasında geçiş yapmak için Model'in nextCellMark() yöntemini çağırır. Hücrenin yeni durumuna bağlı olarak, ilgili düğmeyi ayarlamak veya blokesini kaldırmak için Görünüm'e bir istek gönderilir. Ve sonunda, Modelin mevcut durumunu görüntülemek için Görünüm görünümü tekrar güncellenir.

Modeli, Görünümü ve Denetleyiciyi Birleştirin

Şimdi geriye sadece MVC modeline dayalı Mayın Tarlası uygulamamızdaki tüm öğeleri bağlamak ve oyunu çalıştırmak kalıyor:

Model = Mayın TarlasıModel() denetleyici = Mayın TarlasıController(model); görünüm = Mayın TarlasıView(model, denetleyici) view.pack() view.mainloop()

Çözüm

Bu yüzden MVC modelini düşündük. Teoriyi kısaca gözden geçirelim. Ardından, tkinter grafik modülünü kullanarak problem tanımı ve mimari tasarımdan Python programlama dilinde uygulamaya kadar adım adım tam teşekküllü bir oyun uygulaması oluşturdular.



Fok
Konunun devamı:
pencereler

Natalya Komarova , 28/05/2009 (03/25/2018) Bir forum veya blog okuduğunuzda, gönderilerin yazarlarını takma adla ve ... kullanıcının resmiyle, sözde avatarla hatırlarsınız ....