نحوه راه اندازی گوشی های هوشمند و رایانه های شخصی. پرتال اطلاعاتی

تقسیم کد. مدل MVC

چارچوب بوت استرپ: چیدمان پاسخگو سریع

یک دوره ویدیویی گام به گام در مورد اصول اولیه چیدمان واکنش گرا در چارچوب بوت استرپ.

با استفاده از یک ابزار قدرتمند و کاربردی، حروفچینی ساده، سریع و کارآمد را بیاموزید.

برای سفارش آرایش کنید و پول بگیرید.

دوره رایگان "وب سایت در وردپرس"

آیا می خواهید به CMS وردپرس مسلط شوید؟

آموزش طراحی وب سایت و چیدمان در وردپرس.

یاد بگیرید که با تم ها کار کنید و طرح بندی را برش دهید.

دوره رایگان تصویری طراحی وب سایت، طرح بندی و نصب آن در CMS WordPress!

* ماوس را برای توقف پیمایش.

عقب به جلو

رویکرد مناسب برای توسعه وب: مدل MVC

MVC چیست؟به طور خلاصه، این یک رویکرد توسعه است که به شما امکان می دهد به کد ساختاریافته تر و برنامه به طور کلی دست پیدا کنید.

MVC مخفف "Model-View-Controller" (Model-View-Controller) است. بیایید در مورد این با جزئیات بیشتر صحبت کنیم.

تا به امروز، دو روش معمولی برای ایجاد برنامه های کاربردی وب (سایت ها) وجود دارد.

راه اول، بیایید آن را "کلاسیک" بنامیم، فرض می کنیم که یک فایل می تواند حاوی کدهای مختلف زبان های برنامه نویسی و نشانه گذاری باشد.

مثلاً در ابتدای فایل، یک پرس و جو از پایگاه داده انجام می شود تا اطلاعاتی از آن به دست آید. در اینجا ما با زبان SQL سر و کار داریم - یک زبان پرس و جو ویژه که برای تعامل با پایگاه داده طراحی شده است.

پس از آن، به عنوان یک قاعده، نشانه گذاری html صفحه شروع می شود (کجا بدون آن؟). علاوه بر این، در داخل نشانه گذاری html، کد PHP در مکان های مناسبی درج شده است که منطق آن سایت را کنترل می کند. کل ما در یک فایل داریم: SQL، (X)HTML و PHP. این در حال حاضر یک هوج است. فراموش نکنید که برای تکمیل تصویر، CSS بیشتر و مقداری جاوا اسکریپت را در اینجا اضافه کنید و در نهایت چنان به هم می خوریم که خود شیطان پایش را در این فایل می شکند.

البته، در ابتدا به یاد خواهید آورد که چه چیزی و چگونه در آن اتفاق می افتد، چرا به چه چیزی نیاز دارید، و در کجا باید تغییراتی برای افزودن / حذف / اصلاح عملکردهای خاص ایجاد کنید. با این حال، من به شما تضمین می دهم که تا چند ماه دیگر با گیجی به کد خود نگاه خواهید کرد، سعی می کنید به یاد بیاورید که چه چیزی با چه چیزی مرتبط است، چه تغییراتی پس از تغییر یک فایل "کشیده" می شود و غیره.

من نمی گویم که باید این رویکرد را به طور کامل کنار گذاشت، اما واضح است که باید عاقلانه و بسیار دقیق از آن استفاده کرد.

راه دوممرتبط با این طرح "Model-View-Controller".

ماهیت این رویکرد چیست و چگونه استفاده از آن می تواند به شما در کارتان کمک کند؟

ایده اصلی این رویکرد نیاز است جداسازی عناصر همگن به فایل های مختلف. به بیان خیلی ساده: یک فایل - یک زبان. اما این یک مثال بسیار خام است. این بسیار نادر است.

جدا از ایده جداسازی زبان های مختلف به فایل های مختلف، یک مفهوم کلیدی نیز وجود دارد تقسیم فایل ها به گروه ها با توجه به عملکردهایی که در برنامه انجام می دهند.

در اینجا ما با شما شروع می کنیم تا به بررسی دقیق تر مدل MVC بپردازیم.

این مدل به معنای تقسیم تمام فایل های درگیر در توسعه سایت به دو دسته است سه گروه:

1. فایل های گروه "مدل".
2. فایل های گروه "کنترل کننده".
3. فایل های گروه "نما".

در اینجا مهم است که فوراً درک کنید که نام طرح MVC یک قرارداد است. البته در برنامه شما مدل ها، کنترلرها و نماهای زیادی می تواند وجود داشته باشد (یعنی فایل هایی که با توجه به عملکردهایی که انجام می دهند و ساختار داخلی زیر مجموعه این گروه ها قرار می گیرند).

پس بیایید نگاهی به یک نمودار مقایسه ای از مدل MVC و روش توسعه "کلاسیک"..


در سمت چپ دقیقاً همان چیزی را می بینید که در بالا در مورد آن صحبت کردیم. در بالای صفحه - پرس و جوهای SQL به پایگاه داده. سپس نشانه گذاری به همراه PHP درج می شود.

در سمت راست ساده ترین نمودار مدل MVC است. تحت این طرح در مدل عملیات مربوط به تعامل با پایگاه داده وجود دارد: استخراج داده ها، اصلاح و حذف آن، شمارش تعداد رکوردها در جداول خاص و غیره.

کنترلر حاوی منطق برنامه است، یعنی چه چیزی عملکرد آن را تعیین می کند.

نمای به منظور نمایش به کاربر نهایی است..

فلش های دو سر در نمودار نشان می دهد که یک رابطه در جفت مدل-کنترل کننده و کنترلر-نما وجود دارد. بیایید با استفاده از مثال طرح زیر این رابطه را با جزئیات بیشتری در نظر بگیریم.


در این نمودار، ما دو عنصر جدید اضافه کرده ایم: مرورگر کاربر و پایگاه داده. بیایید نگاهی به کل چرخه بیندازیم:از زمانی که مرورگر به یک url خاص ضربه می زند تا زمانی که صفحه به کاربر ارائه شود:

1. کاربر آدرسی را وارد می کند و مرورگر به کنترلر دسترسی پیدا می کند.

2. کنترلر به مدل دسترسی پیدا می کند.

3. مدل به پایگاه داده دسترسی پیدا می کند (مثلاً برای به دست آوردن اطلاعات لازم برای خروجی)

4. اطلاعات پایگاه داده به مدل برمی گردد.

5. اطلاعات از مدل به کنترلر منتقل می شود.

6. کنترلر این اطلاعات را به view منتقل می کند.

7. نمایش با استفاده از یک کنترلر به مرورگر ارائه می شود.

این طرح کلی این مدل است. همانطور که می بینید، مرورگر و پایگاه داده در این طرح تا حدودی از هم جدا هستند. واقعا، مرورگر فقط می تواند به کنترلر دسترسی داشته باشد زیرا کنترلر بخشی از URL است. بازدید کننده نمی تواند به چیزی غیر از کنترلر دسترسی داشته باشد. درک این مهم است. شخص نمی تواند از طریق نوار آدرس به نماها یا مدل ها دسترسی داشته باشد. فقط با کنترلر تعامل دارد.

در این راستا می توان از کنترلر به عنوان نوعی «مرکز توزیع» صحبت کرد. خودتان ببینید: کنترل کننده درخواست های کاربر را پردازش می کند، کنترل کننده به مدل دسترسی پیدا می کند، کنترل کننده واسطه ای برای نمایش نما در مرورگر است.

دومین عنصری که جداست پایگاه داده است. و درست است. در چارچوب مفهوم MVC، پذیرفته شده است که فقط مدل ها باید با پایه کار کنندبا این حال، گاهی اوقات این اصل نقض می شود. در این حالت تعامل با پایگاه داده از کنترلر یا حتی view انجام می شود.

البته نباید با زیر پا گذاشتن ساختار و اصول MVC زیاده روی کرد، اما گاهی اوقات چنین انحرافی از قوانین می تواند از نظر بهبود خوانایی کد و درک طرح کاری اپلیکیشن بسیار مفید باشد.

مدلراستی، یک عنصر اختیاری در طرح MVC است. پیاده سازی هر چیزی که نیاز است بدون استفاده از مدل ها در اصل کاملاً امکان پذیر است. طبیعتاً در این حالت شما از طریق کنترلر با پایگاه داده در تعامل خواهید بود و فایل ها را مشاهده خواهید کرد. همانطور که قبلاً فهمیدید، این لحن خیلی خوبی نیست. هنگامی که تصمیم گرفتید با این مفهوم کار کنید، توصیه می شود از مدل ها استفاده کنید و آن را برای هدف مورد نظر خود انجام دهید.

ما موارد "افراطی" را بررسی کردیم و تثلیث ما در مرکز طرح باقی ماند، جایی که فعل و انفعالات "Model - Controller" و "Controller - View" انجام می شود.

پس از مطالعه اصول اولیه این مدل، می‌توانیم به این فکر کنیم که این رویکرد چه چیزی به ما می‌دهد و چرا آن را بر مدل کلاسیک ترجیح می‌دهد.

مزیت اصلی استفاده از چنین طرحی در کار من قبلاً ذکر شده است - این است افزایش ساختار کد و برنامه به طور کلی. بر کسی پوشیده نیست که مدل MVC توسط بسیاری از سازندگان فریمورک پذیرفته شده است، که در میان آنها CodeIgniter مورد علاقه من است.

بالاخره چارچوب چیست؟اگر کلمه خارجی را کنار بگذاریم، پس این فقط یک چارچوب است، یک ساختار مشخص، که طبق آن از شما برای توسعه یک سایت دعوت می شود. این ساختار به اندازه کافی همه کاره است تا تقریباً هر سایتی را با آن ایجاد کند. در عین حال، که بسیار مهم است، چارچوب نیز بسیار انعطاف‌پذیر است و به شما امکان می‌دهد دقیقاً به آنچه نیاز دارید برسید.

به عبارت دیگر، یک فریم ورک یک چارچوب انعطاف پذیر است که شما را از نظر ساختار محدود می کند، اما شما را از نظر عملکرد محدود نمی کند.

با بازگشت به سوال MVC، می بینید که بسیاری از فریمورک ها دقیقاً از این رویکرد استفاده می کنند: آنها یک ساختار برنامه نسبتاً واضح ارائه می دهند که همچنین فایل ها را به view ها، مدل ها و کنترلرها تقسیم می کند. اگر یک بار آن را صرف یادگیری نحوه استفاده از چارچوب و مدل MVC کنید، همه اینها با هم می توانند در زمان شما صرفه جویی کنند.

از دیگر مزایای مدل MVC می توان به تقسیم کد بر اساس تابع. دیگر نیازی به کاوش در "بهم ریختگی" پرس و جوهای SQL، نشانه گذاری و کدهای PHP نخواهید داشت. اگر نیاز به اصلاح یا تغییر چیزی دارید، دقیقاً می دانید که کدام فایل را باید ویرایش کنید.

در زیر می توانید بخشی از فایل مربوط به گروه "نما" را مشاهده کنید:


و این هم یک قطعه کد از مدل:


کنترلر ممکن است به شکل زیر باشد:


یک مزیت بسیار مهم، همانطور که می بینید، این است جدا کردن نما از کد. اغلب لازم است به نحوی طراحی یا حتی ساختار سایت را تغییر دهیم، در حالی که همان اطلاعاتی را که در صفحه نمایش داده شده بود حفظ کنیم. و در اینجا ویرایش یک هش کد شروع می شود که به مرور زمان سخت تر می شود.

مزیت مدل MVC دقیقاً در توانایی کامل آن نهفته است هنگام تغییر منطق برنامه، ویرایش طراحی سایت را حذف کنید. شما می توانید هر یک از سه عنصر را تغییر دهید: Model، View، Controller. در این مورد، شما مجبور نیستید تغییراتی در سایر عناصر ایجاد کنید، زیرا آنها تا حدی مستقل هستند.

موضوع استقلال مدل ها و نماها به ویژه مرتبط است. پس از نوشتن، معمولاً می توانید با موفقیت از آنها برای پروژه های مختلف با حداقل ویرایش یا بدون ویرایش استفاده کنید. این امر با اجتناب از نوشتن مجدد کدهای مشابه در زمان شما صرفه جویی می کند.

مزایای استفاده از مدل MVC در چارچوب آشکار استبه عنوان مثال، همان CodeIgniter.

بر کسی پوشیده نیست که هر سایتی تعداد زیادی ویژگی مشابه، اگر نگوییم یکسان، دارد. کافی است فرم بازخورد یا پیمایش صفحه را به خاطر بسپارید. اینها فقط درخشان ترین لحظات "خارجی" هستند. شباهت‌های بیشتری را در کدهایی خواهید دید که برای کاربر معمولی قابل مشاهده نیستند، در کدهایی که روی سرور اجرا می‌شود.

تقریباً همه توسعه دهندگان وب با نیاز به استفاده از توابع مشابه PHP، ایجاد پرس و جو در پایگاه داده مشابه و غیره مواجه هستند. سازندگان فریم‌ورک در اینجا کار بسیار مهمی انجام داده‌اند - آنها سعی کرده‌اند آن دسته از توابع را که اغلب مورد استفاده قرار می‌گیرند در فایل‌های جداگانه گروه‌بندی کنند و فرصت‌های جدیدی را برای وب‌مسترها و برنامه‌نویسان وب فراهم کنند.

اکنون می‌توانید کارهای ضروری را بدون اینکه واقعاً در مورد اجرای آنها فکر کنید، انجام دهید. می توانید به جای چند ده خط، چند خط کد بنویسید و در وقت خود صرفه جویی کنید تمرکز بیشتر بر روی منطق برنامه، و نه بر نحوه پیاده سازی آن.

و همه اینها در چارچوب مفهوم MVC اتفاق می افتد و به شما این امکان را می دهد که تقریباً به هر نتیجه ای با استفاده از چارچوب برسید. در عین حال، درجه بالایی از خوانایی کد را دریافت می کنید. چه چیز دیگری برای کار راحت و سازنده نیاز دارید؟

پس گفتار:فراموش نکنید که هر ساختاری که برای آسان کردن برخی کارها ایجاد شده است برای آسان کردن کار ایجاد شده است.

در مواردی که مطمئن هستید که این برای درک شما از ساختار برنامه بد است، نباید به اصل MVC پایبند باشید. شما نباید زیر مدل خم شوید، بلکه او زیر شما.

دیمیتری نائومنکو

P.S.به این فکر می کنید که بر کدام فریم ورک پی اچ پی مسلط شوید؟ به CakePHP توجه کنید - الگوی MVC مورد بحث در بالا را پیاده سازی می کند، و در حال حاضر می توانید یک دوره کوتاه ویدیویی مقدماتی برای دریافت ایده کلی از قابلیت های این چارچوب دریافت کنید:

مطالب را دوست داشتید و می خواهید تشکر کنید؟
فقط با دوستان و همکاران خود به اشتراک بگذارید!


الگوی Model-View-Controller (MVC) هنگام ساخت برنامه هایی با رابط کاربری گرافیکی یا رفتارهای پیچیده بسیار مفید است. اما برای موارد ساده تر نیز مناسب است. در این پست یک بازی مین روب را که حول این الگو طراحی شده است می سازیم. پایتون به عنوان زبان توسعه انتخاب شد، اما هیچ اهمیت خاصی در این مورد وجود ندارد. الگوها به زبان برنامه نویسی خاصی بستگی ندارند و می توانید به راحتی پیاده سازی حاصل را به هر پلتفرم دیگری منتقل کنید.

تبلیغات

مختصری در مورد الگوی MVC

همانطور که از نام آن پیداست، الگوی MVC دارای 3 جزء است: Model، View و Controller. هر یک از اجزاء نقش خود را انجام می دهند و قابل تعویض هستند. این بدان معنی است که مؤلفه ها تنها توسط برخی از رابط های واضح به یکدیگر متصل می شوند که هر پیاده سازی می تواند پشت آنها قرار گیرد. این رویکرد به شما امکان می دهد اجزای مختلف را جایگزین و ترکیب کنید و منطق لازم کار یا ظاهر برنامه را ارائه دهید. بیایید به عملکردهایی که هر جزء انجام می دهد نگاه کنیم.

مدل

مسئول منطق داخلی برنامه است. در اینجا می توانیم راه های ذخیره سازی داده ها و همچنین قوانین و الگوریتم های پردازش اطلاعات را پنهان کنیم.

به عنوان مثال برای یک برنامه می توانیم چندین مدل ایجاد کنیم. یکی اشکال زدایی می کند و دیگری کار می کند. اولی می تواند داده های خود را در حافظه یا در یک فایل ذخیره کند و دومی قبلاً از پایگاه داده استفاده می کند. در واقع، این فقط یک الگوی استراتژی است.

نمایندگی

مسئول نمایش داده های مدل. در این سطح، ما فقط یک رابط برای تعامل کاربر با Model ارائه می دهیم. نکته معرفی این مؤلفه همانند ارائه روش های مختلف ذخیره سازی داده ها بر اساس چندین مدل است.

به عنوان مثال، در مراحل اولیه توسعه، می توانیم یک نمای کنسول ساده برای برنامه خود ایجاد کنیم و تنها پس از آن یک رابط کاربری گرافیکی با طراحی زیبا اضافه کنیم. علاوه بر این، امکان ذخیره هر دو نوع رابط وجود دارد.

ضمناً باید در نظر داشت که مسئولیت View فقط نمایش به موقع وضعیت مدل است. کنترلر مسئول پردازش اقدامات کاربر است که اکنون در مورد آن صحبت خواهیم کرد.

کنترل کننده

پیوندی بین مدل و اقدامات کاربر ناشی از تعامل با View ارائه می دهد. زمانی که حالت‌های Model و View به‌روزرسانی می‌شوند، مختصات را مشخص می‌کند. بیشتر تصمیمات را در مورد انتقال برنامه از یک حالت به حالت دیگر می گیرد.

در واقع برای هر اقدامی که کاربر می تواند در View انجام دهد، باید یک handler در Controller تعریف شود. این کنترلر دستکاری های مناسب را بر روی مدل انجام می دهد و در صورت لزوم، مشاهده را از وجود تغییرات مطلع می کند.

تبلیغات

مشخصات بازی Minesweeper

تئوری بس است حالا بیایید به سراغ تمرین برویم. برای نشان دادن الگوی MVC، یک بازی ساده می نویسیم: Minesweeper. قوانین بازی بسیار ساده است:

  1. زمین بازی یک منطقه مستطیلی است که از سلول ها تشکیل شده است. مین ها به طور تصادفی در برخی سلول ها قرار می گیرند، اما بازیکن از آنها اطلاعی ندارد.
  2. بازیکن می تواند با دکمه های چپ یا راست ماوس روی هر سلول زمین بازی کلیک کند.
  3. با کلیک بر روی دکمه سمت چپ ماوس سلول باز می شود. در این صورت، اگر مین در سلول وجود داشته باشد، بازی با باخت به پایان می رسد. اگر در سلول های مجاور مین وجود داشته باشد، در کنار سلول باز، شمارنده ای با تعداد مین های اطراف در سلول باز نمایش داده می شود. اگر در اطراف یک سلول باز مین وجود نداشته باشد، هر سلول مجاور طبق همان اصل باز می شود. یعنی سلول ها تا زمانی باز می شوند که یا به مرز زمین بازی برخورد کنند یا به سلول های باز شده برسند یا در کنار آنها مین وجود داشته باشد.
  4. با کلیک بر روی دکمه سمت راست ماوس می توانید علامت هایی را روی سلول ها ایجاد کنید. با کلیک بر روی یک سلول بسته آن را با یک پرچم مشخص می کند که حالت آن را قفل می کند و از باز شدن تصادفی آن جلوگیری می کند. با کلیک بر روی سلولی که با پرچم مشخص شده است، پرچم آن به علامت سوال تبدیل می شود. در این حالت سلول دیگر مسدود نیست و با دکمه سمت چپ ماوس باز می شود. با کلیک بر روی سلولی با علامت سوال، حالت بسته بدون علامت آن باز می گردد.
  5. پیروزی با وضعیت بازی تعیین می شود که در آن تمام سلول های زمین بازی به استثنای سلول های استخراج شده باز هستند.

نمونه ای از آنچه به دست می آوریم در زیر نشان داده شده است:

نمودارهای UML Minesweeper

قبل از شروع به نوشتن کد، بهتر است از قبل به معماری برنامه فکر کنید. این نباید به زبان پیاده سازی بستگی داشته باشد، بنابراین UML برای اهداف ما مناسب است.

نمودار وضعیت سلولی بازی

هر سلول در زمین بازی می تواند در یکی از 4 حالت باشد:

  1. سلول بسته است.
  2. قفس باز است؛
  3. سلول پرچم گذاری شده است.
  4. سلول با علامت سوال مشخص شده است.

در اینجا ما فقط حالت هایی را تعریف کرده ایم که مربوط به View هستند. از آنجایی که مین ها در طول بازی نمایش داده نمی شوند، وضعیت مربوطه نیز در مجموعه پایه پیش بینی نشده است. بیایید با استفاده از نمودارهای وضعیت UML، انتقال های ممکن از یک وضعیت سلولی به حالت دیگر را تعریف کنیم:

نمودار کلاس مین یاب

از آنجایی که تصمیم گرفتیم برنامه خود را بر اساس الگوی MVC بسازیم، سه کلاس اصلی خواهیم داشت: MinesweeperModel، MinesweeperView و MinesweeperController، و همچنین یک کلاس کمکی MinesweeperCell برای ذخیره وضعیت سلول. نمودار کلاس آنها را در نظر بگیرید:

سازماندهی معماری بسیار ساده است. در اینجا ما به سادگی وظایف را مطابق با اصول الگوی MVC بین هر کلاس توزیع کرده ایم:

  1. در انتهای این سلسله مراتب، کلاس سلول بازی MinesweeperCell قرار دارد. موقعیت سلول را ذخیره می کند که توسط ردیف ردیف و ستون ستون زمین بازی تعیین می شود. یکی از ایالت ها بیان می کند که در بخش فرعی قبلی توضیح دادیم. اطلاعاتی در مورد وجود مین ها در سلول (مین گذاری شده) و شمارنده مین ها در شمارنده سلول های همسایه. علاوه بر این، دو روش دارد: nextMark() برای چرخش در حالت های علامت راست کلیک، و open() که رویداد کلیک چپ را کنترل می کند.
  2. کمی بالاتر کلاس MinesweeperModel Model است. این ظرف سلول بازی MinesweeperCell است. اولین متد startGame () آن، زمین بازی را برای شروع بازی آماده می کند. متد isWin () زمین بازی را برای وضعیت برد بررسی می کند و اگر بازیکن برنده شده باشد true را برمی گرداند، در غیر این صورت false را برمی گرداند. یک روش مشابه isGameOver() برای بررسی ضرر در نظر گرفته شده است. متدهای openCell() و nextCellMark() فقط اقدامات را به سلول های مربوطه در زمین بازی واگذار می کنند و متد getCell() سلول بازی درخواستی را برمی گرداند.
  3. کلاس MinesweeperView View شامل متدهای زیر است: syncWithModel() - ترسیم مجدد View را برای نمایش وضعیت فعلی زمین بازی در Model فراهم می کند. getGameSettings() - تنظیمات بازی تنظیم شده توسط کاربر را برمی گرداند. createBoard() - یک زمین بازی بر اساس داده های Model ایجاد می کند. () showWinMessage و showGameOverMessage() به ترتیب پیام های برد و باخت را نمایش می دهند.
  4. و در نهایت کلاس MinesweeperController Controller. فقط سه روش برای هر اقدام احتمالی بازیکن تعریف می کند: startNewGame() مسئول کلیک کردن بر روی دکمه "بازی جدید" در رابط View است. onLeftClick() و onRightClick() به ترتیب با کلیک روی سلول های بازی با دکمه های چپ و راست ماوس را کنترل می کنند.

اجرای بازی Minesweeper در پایتون

زمان آن رسیده است که اجرای پروژه خود را شروع کنیم. ما پایتون را به عنوان زبان توسعه انتخاب می کنیم. سپس کلاس View را بر اساس ماژول tkinter می نویسیم.

اما بیایید با مدل شروع کنیم.

MinsweeperModel

پیاده سازی مدل در پایتون به صورت زیر است:

MIN_ROW_COUNT = 5 MAX_ROW_COUNT = 30 MIN_COLUMN_COUNT = 5 MAX_COLUMN_COUNT = 30 MIN_MINE_COUNT = 1 MAX_MINE_COUNT = 800 کلاس MinesweeperCell: # حالت سلول بازی احتمالی: # بسته - بسته شده # باز شده، ستون باز شده - rowin .row = ردیف self.column = ستون self.state = "بسته" self.mined = اشتباه self.counter = 0 markSequence = [ "بسته"، "پرچمدار"، "پرسش شده" ] def nextMark (self): اگر خود. حالت در self.markSequence: stateIndex = self.markSequence.index(self.state) self.state = self.markSequence[ (stateIndex + 1) % len(self.markSequence) ] def open(self): if self.state ! = "flagged": self.state = "opened" class MinesweeperModel: def __init__(self): self.startGame() def startGame(self, rowCount = 15, columnCount = 15, mineCount = 15) : اگر تعداد ردیف ها در محدوده (MIN_ROW) , MAX_ROW_COUNT + 1): self.rowCount = rowCount اگر تعداد ستونها در محدوده (MIN_COLUMN_COUNT، MAX_COLUMN_COUNT + 1): self.columnCount = تعداد ستون اگر mineCount< 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)

در بالا، محدوده تنظیمات مجاز بازی را تعریف می کنیم:

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

به طور کلی، این تنظیمات را می توان بخشی از مدل نیز کرد. با این حال، اندازه میدان و تعداد مین ها اطلاعات کاملا ثابتی است و بعید است اغلب تغییر کند.

سپس کلاس سلول بازی MinesweeperCell را تعریف کردیم. معلوم شد که او بسیار ساده است. در سازنده کلاس، فیلدهای سلول با مقادیر پیش فرض مقداردهی اولیه می شوند. در مرحله بعد، برای ساده سازی اجرای انتقال حالت چرخه ای، از لیست کمکی markSequence استفاده می کنیم. اگر سلول در حالت "باز" ​​باشد که در این لیست گنجانده نشده است، در متد ()nextMark هیچ اتفاقی نمی افتد، در غیر این صورت سلول وارد حالت بعدی می شود و از آخرین حالت "پرسش"، " پرش" به حالت اولیه "بسته" ". در متد open() وضعیت سلول را بررسی می کنیم و اگر برابر با "flagged" نباشد، سلول به حالت "opened" می رود.

آنچه در زیر می آید تعریف کلاس MinesweeperModel Model است. متد startGame() زمین بازی را با توجه به پارامترهای rowCount، columnCount و mineCount ارائه می‌کند. برای هر یک از پارامترها، بررسی می شود که آیا در محدوده مجاز مقادیر قرار می گیرد یا خیر. اگر مقدار ارسال شده خارج از محدوده باشد، مقدار پارامتر زمین بازی تغییر نمی کند. لازم به ذکر است برای تعداد معادن چک تکمیلی در نظر گرفته شده است. اگر تعداد مین های منتقل شده از اندازه میدان بیشتر شود، آن را به تعداد سلول های بدون یک محدود می کنیم. هر چند که البته چنین بازی چندان منطقی نیست و در یک مرحله کامل می شود، بنابراین می توانید برای چنین موردی به نوعی قانون خود را در نظر بگیرید.

زمین بازی به عنوان لیستی از لیست سلول ها در متغیر سلول های جدول ذخیره می شود. علاوه بر این، لطفاً توجه داشته باشید که در متد startGame() فقط مقدار موقعیت برای سلول ها تنظیم شده است، اما ماین ها هنوز قرار نگرفته اند. در عوض، متغیر firstStep با مقدار True تعریف می‌شود. این برای حذف عنصر شانس از حرکت اول و جلوگیری از ضرر آنی ضروری است. مین ها پس از اولین حرکت در سلول های باقی مانده قرار می گیرند.

متد getCell() به سادگی سلول زمین بازی را با سطر سطر و ستون ستون برمی گرداند. اگر مقدار سطر یا ستون نامعتبر باشد، None برگردانده می شود.

متد isWin() True را برمی‌گرداند اگر تمام سلول‌های باز نشده باقیمانده در زمین بازی استخراج شوند، یعنی در صورت پیروزی، در غیر این صورت False را برمی‌گرداند. متد isGameOver() به سادگی مقدار ویژگی کلاس gameOver را برمی گرداند.

در روش openCell() فراخوانی open() به شی سلول بازی که در موقعیت مشخص شده در پارامترهای متد در زمین بازی قرار دارد، واگذار می شود. اگر سلول باز استخراج شده باشد، مقدار gameOver را روی True قرار می دهیم و از روش خارج می شویم. اگر بازی هنوز تمام نشده است، با بررسی مقدار firstStep به دنبال این هستیم که ببینیم آیا این اولین حرکت است یا خیر. اگر حرکت واقعا اولین حرکت باشد، پس از آن ماین ها با استفاده از متد helpergeneMines() در زمین بازی قرار می گیرند که کمی بعد در مورد آن صحبت خواهیم کرد. در مرحله بعد، تعداد سلول‌های همسایه استخراج شده را می‌شماریم و مقدار مربوط به ویژگی شمارنده را برای سلول پردازش شده تعیین می‌کنیم. اگر شمارنده صفر باشد، با استفاده از متد getCellNeighbors() لیستی از سلول‌های همسایه را درخواست می‌کنیم و به صورت بازگشتی متد openCell() را برای همه «همسایگان» بسته، یعنی برای سلول‌های با وضعیت «بسته» فراخوانی می‌کنیم.

متد ()nextCellMark به سادگی فراخوانی را به متد nextMark() برای سلول در موقعیت داده شده واگذار می کند.

ماین ها در متدgeneMines() قرار می گیرند. در اینجا ما فقط به صورت تصادفی موقعیتی را در زمین بازی انتخاب می کنیم و بررسی می کنیم که سلول در این موقعیت باز نیست و قبلاً ماین نشده است. اگر هر دو شرط وجود داشته باشد، مقدار مشخصه استخراج شده را روی True قرار می دهیم، در غیر این صورت به جستجوی سلول آزاد دیگری ادامه می دهیم. فراموش نکنید که برای استفاده از ماژول تصادفی در پایتون، باید به طور صریح آن را با دستور import random وارد کنید.

متد countMinesAroundCell() برای شمارش تعداد مین‌های اطراف یک سلول مشخص از زمین بازی کاملاً بر اساس متد getCellNeighbors () است. درخواست "همسایگان" سلول در متد getCellNeighbors() نیز بسیار ساده پیاده سازی می شود. فکر نمی کنم با آن مشکلی داشته باشید.

MinesweeperView

حالا بریم سراغ ارائه. کد کلاس MinesweeperView در پایتون در زیر نشان داده شده است:

Class MinesweeperView(Frame): def __init__(self, model, controller, والد = هیچکدام): Frame.__init__(self, والد) self.model = model self.controller = controller self.controller.setView(self) self.createBoard( ) panel = قاب (خود) panel.pack(side = BOTTOM، fill = X) Button(panel، text = "New Game"، command = self.controller.startNewGame). بسته(سمت راست) self.mineCount = StringVar (panel) self.mineCount.set(self.model.mineCount) Spinbox(panel, from_ = MIN_MINE_COUNT, to = MAX_MINE_COUNT, textvariable = self.mineCount, width = 5).pack(side = RIGHT) Label(panel, text = " تعداد دقیقه: ".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 , عرض = 5). بسته (سمت = RIGHT) Label(panel, text = "x"). بسته(سمت راست) self.columnCount = StringVar(panel) self.columnCount.set(self.model.columnCount) Spinbox (پانل، از_ = MIN_COLUMN_COUN T، به = MAX_COLUMN_COUNT، متغیر متن = self.columnCount، عرض = 5). بسته (سمت راست = RIGHT) برچسب (پانل، متن = "اندازه فیلد:"). بسته (سمت راست = RIGHT) def syncWithModel(self): برای ردیف در محدوده (self.model.rowCount): برای ستون در محدوده (self.model.columnCount): cell = self.model.getCell(ردیف، ستون) اگر سلول: btn = self.buttonsTable[ row ][ column ] if self .model.isGameOver() و cell.mined: btn.config(bg = "مشکی"، متن = "") if cell.state == "بسته": btn.config(text = "") elif cell.state = = "opened": btn.config(relief = SUNKEN، text = "") if cell.counter > 0: btn.config(text = cell.counter) elif cell.mined: btn.config(bg = "قرمز") elif cell.state == "پرچم گذاری شده": btn.config(text = "P") elif cell.state == "پرسش شده": btn.config(text = "?") def blockCell(خود، ردیف، ستون، بلوک = True): btn = self.buttonsTable[ row ][ column ] if not btn: return if block: btn.bind(" "، "شکستن") else: btn.unbind(" ") def getGameSettings(self): return self.rowCount.get(), self.columnCount.get(), self.mineCount.get() def createBoard(self): try: 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) به جز: pass self.board = Frame(self ) self.board.pack() self.buttonsTable = برای ردیف در محدوده (self.model.rowCount): خط = قاب (self.board) line.pack (side = TOP) self.buttonsRow = برای ستون در محدوده (self) مدل btn.pack(side = LEFT) btn.bind(" "، lambda e، ردیف = ردیف، ستون = ستون: self.controller.onRightClick(ردیف، ستون)) self.buttonsRow.append(btn) self.buttonsTable.append(self.buttonsRow) def showWinMessage(self): showinfo( "تبریک!"، "تو برنده شدی!") def showGameOverMessage(self): showinfo("بازی تمام شد!"، "شما باختید!")

نمای ما بر اساس کلاس Frame از ماژول tkinter است، بنابراین فراموش نکنید که دستور import مناسب را اجرا کنید: from tkinter import * . در سازنده کلاس، Model و Controller پاس داده می شوند. متد ()createBoard بلافاصله فراخوانی می شود تا زمین بازی را از سلول ها ترسیم کند. پیشاپیش می گویم که برای این منظور از دکمه های معمولی Button استفاده می کنیم. سپس یک Frame ایجاد می شود که به عنوان پنل پایینی برای تعیین گزینه های بازی عمل می کند. در این پنل، دکمه "بازی جدید" را به صورت متوالی قرار می دهیم که کنترل کننده آن با متد ()startNewGame به Controller ما تبدیل می شود و سپس سه شمارنده Spinbox را قرار می دهیم تا بازیکن بتواند اندازه زمین بازی و تعداد مین ها را مشخص کند. .

متد syncWithModel() به سادگی از طریق هر سلول بازی دو بار حلقه می زند و ظاهر دکمه ای را که آن را در رابط کاربری گرافیکی ما نشان می دهد تغییر می دهد. برای سادگی، از نمادهای متنی برای نمایش نمادها استفاده کردم، با این حال، تغییر متن به گرافیک از فایل های گرافیکی خارجی چندان دشوار نیست.

همچنین توجه داشته باشید که ما از سبک دکمه SUNKEN برای نمایش سلول باز استفاده می کنیم. و در صورت باخت، مکان تمام مین ها را در زمین بازی باز می کنیم و دکمه های مربوطه را به رنگ مشکی نشان می دهیم و دکمه مربوط به آخرین سلول باز با مین با رنگ قرمز برجسته می شود:

متد ()blockCell زیر به عنوان کمک کننده عمل می کند و به کنترل کننده اجازه می دهد تا حالت مسدود کردن دکمه ها را تنظیم کند. این برای جلوگیری از باز شدن تصادفی سلول‌های بازی که با یک پرچم مشخص شده‌اند، انجام می‌شود و با تنظیم یک کنترل‌کننده خالی کلیک چپ ماوس به دست می‌آید.

متد getGameSettings() فقط مقادیر شمارنده های قرار داده شده در پانل پایین را با اندازه زمین بازی و تعداد مین ها برمی گرداند.

ایجاد نمایش زمین بازی در متد ()createBoard انجام می شود. اول از همه، سعی می کنیم در صورت وجود زمین بازی قدیمی را حذف کنیم و همچنین سعی می کنیم مقادیر شمارنده ها را مطابق با پیکربندی فعلی Model از پانل تنظیم کنیم. سپس یک Frame جدید ایجاد می شود که ما آن را board می نامیم تا میدان بازی را نشان دهد. ما جدول دکمه‌ها را مطابق با همان اصل سلول‌های بازی در مدل با استفاده از یک حلقه دوتایی می‌سازیم. کنترل‌کننده‌های هر دکمه به روش‌های onLeftClick() و onRightClick()Controller برای کلیک کردن روی دکمه‌های چپ و راست ماوس به ترتیب مقید هستند.

دو روش آخر، showWinMessage() و showGameOverMessage()، فقط کادرهای محاوره ای را با پیام های مناسب با استفاده از تابع showinfo() نمایش می دهند. برای استفاده از آن، باید یک ماژول دیگر وارد کنید: از tkinter.messagebox import * .

Minesweeper Controller

در اینجا به پیاده سازی Controller می رسیم:

Class MinesweeperController: def __init__(self, model): self.model = model def setView(self, view): self.view = view def startNewGame(self): gameSettings = self.view.getGameSettings() try: self.model. startGame(*map(int, gameSettings)) به جز: self.model.startGame(self.model.rowCount, self.model.columnCount, self.model.mineCount) self.view.createBoard() def onLeftClick(self, row, column): self.model.openCell(ردیف، ستون) self.view.syncWithModel() if self.model.isWin(): self.view.showWinMessage() self.startNewGame() elif self.model.isGameOver(): self.view.showGameOverMessage() self.startNewGame() def RightClick(self, row, column): self.model.nextCellMark(ردیف، ستون) self.view.blockCell(ردیف، ستون، self.model.getCell(ردیف، column).state == "پرچم گذاری شده") self.view.syncWithModel()

برای اتصال View به Controller، متد setView() را اضافه کرده ایم. این به این دلیل است که اگر بخواهیم یک View را به سازنده منتقل کنیم، آن View باید قبل از ایجاد Controller وجود داشته باشد. و سپس چنین راه حلی با یک روش اضافی برای اتصال به سادگی از Controller به View منتقل می شود، که در آن متد setController() ظاهر می شود.

روش کنترل کننده کلیک دکمه New Game startNewGame() ابتدا تنظیمات بازی وارد شده در View را جستجو می کند. پارامترهای بازی به صورت 3 تاپلی برگردانده می شوند که سعی می کنیم آن را به int تبدیل کنیم. اگر همه چیز خوب پیش برود، این مقادیر را به متد ()startGame Model می‌دهیم تا زمین بازی را بسازیم. اگر مشکلی پیش بیاید، ما به سادگی زمین بازی را با پارامترهای قدیمی بازسازی می کنیم. در نهایت با فراخوانی متد ()createBoard درخواستی برای ایجاد یک نمایشگر جدید در View ارسال می کنیم.

کنترل کننده ()onLeftClick ابتدا به مدل می گوید که سلول بازی را در موقعیت انتخابی بازیکن باز کند. سپس به View می گوید که وضعیت مدل تغییر کرده است و پیشنهاد می کند همه چیز را دوباره ترسیم کند. سپس مدل از نظر وضعیت پیروزی یا باخت بررسی می شود. اگر هر یک از این موارد اتفاق افتاد، ابتدا درخواستی برای نمایش اعلان مناسب به View ارسال می‌شود و سپس کنترل‌کننده ()startNewGame برای شروع یک بازی جدید فراخوانی می‌شود.

کلیک راست ماوس در متد onRightClick() انجام می شود. خط اول متد NextCellMark() Model را فراخوانی می کند تا در برچسب سلول بازی انتخاب شده بچرخد. بسته به وضعیت جدید سلول، درخواستی برای تنظیم یا رفع انسداد دکمه مربوطه به View ارسال می شود. و در انتها نمای View دوباره به روز می شود تا وضعیت فعلی Model نمایش داده شود.

مدل، نمایش و کنترلر را ترکیب کنید

اکنون تنها باقی مانده است که همه عناصر موجود در اجرای Minesweeper را بر اساس الگوی MVC وصل کرده و بازی را اجرا کنیم:

Model = MinesweeperModel() controller = MinesweeperController(model); view = MinesweeperView (مدل، کنترلر) view.pack() view.mainloop()

نتیجه

بنابراین الگوی MVC را در نظر گرفته ایم. اجازه دهید به طور خلاصه به نظریه بپردازیم. و سپس آنها یک برنامه بازی کامل را مرحله به مرحله ایجاد کردند، از تعریف مسئله و طراحی معماری به پیاده سازی در زبان برنامه نویسی پایتون با استفاده از ماژول گرافیکی tkinter.

الگو Model-View-Controller (MVC)، که در اواخر دهه 1970 کشف شد، یک الگوی طراحی معماری نرم افزار است که هدف اصلی آن جدا کردن عملکردهای کار با داده ها از نمایش آنها است. از لحاظ تئوری، یک برنامه MVC که به خوبی طراحی شده است به توسعه دهندگان جلویی و بک اند اجازه می دهد در حین کار در زمینه مسئولیت یکدیگر دخالت نکنند، یعنی توسعه دهنده جلویی نیازی به دانستن چیزی در مورد "آشپزخانه" ندارد. همکار پشتیبان او و بالعکس.

اگرچه MVC در ابتدا برای توسعه دسکتاپ طراحی شده بود، اما برای کارهای مدرن اقتباس شده است و در بین توسعه دهندگان وب بسیار محبوب است زیرا ایجاد کد واضح تر و قابل استفاده مجدد از طریق جداسازی نگرانی ها امکان پذیر شده است. الگوی MVC منجر به سیستم‌های شفاف و مدولار می‌شود که به توسعه‌دهندگان اجازه می‌دهد تا خیلی سریع در کد موجود تغییرات ایجاد کنند.

در این مقاله، اصول اولیه MVC را مرور می‌کنیم و با تعریف الگو شروع می‌کنیم و در یک مثال کوچک به کاربرد آن ادامه می‌دهیم. این مقاله در درجه اول برای کسانی مفید خواهد بود که هرگز در زندگی خود با این الگو مواجه نشده اند، و همچنین، شاید، برای کسانی که می خواهند دانش خود را در مورد MVC تازه کنند.

آشنایی با MVC

همانطور که قبلا ذکر شد، نام الگو از مخفف سه کلمه آمده است: مدل (مدل)، مشاهده (مشاهده)و کنترلر (کنترل کننده). به طور خلاصه، اصل الگو را می توان با یک نمودار نشان داد (در ویکی پدیا یافت می شود):

این نمودار به وضوح جریان یک طرفه اطلاعات در الگو را نشان می دهد و همچنین نقش هر جزء را توصیف می کند.

مدل

این مدل برای دسترسی و دستکاری داده ها استفاده می شود. در بیشتر موارد، مدل چیزی است که برای دسترسی به یک ذخیره‌سازی داده (مانند پایگاه داده) استفاده می‌شود. این مدل یک رابط برای بازیابی داده ها، ایجاد داده ها، اصلاح و حذف از ذخیره سازی فراهم می کند. در زمینه الگوی MVC، مدل یک واسطه بین view و کنترل کننده است.

یکی از ویژگی‌های بسیار مهم مدل این است که از نظر فنی هیچ اطلاعی از آنچه با داده‌های موجود در کنترلر و نمای می‌افتد ندارد. مدل هرگز نباید درخواستی از/از سایر اجزای الگو داشته باشد یا انتظار داشته باشد.

با این حال، همیشه به یاد داشته باشید که مدل فقط یک دروازه به یک پایگاه داده یا سیستم دیگر نیست، که فقط به ارسال داده ها به عقب و جلو مربوط می شود. مدل مانند یک دروازه به داده ها است. مدل اغلب پیچیده ترین بخش سیستم است، تا حدی به این دلیل که خود مدل پیوندی به تمام بخش های دیگر است.

نمایندگی

نما جایی است که داده های دریافتی از مدل به شکل دلخواه نمایش داده می شود. در برنامه های کاربردی وب سنتی که در الگوی MVC توسعه یافته اند، نمای بخشی از سیستم است که کد HTML در آن تولید می شود. View همچنین مسئول دریافت اقدامات از کاربر به منظور ارسال آنها به کنترلر است. به عنوان مثال، یک view دکمه ای را در رابط کاربری نمایش می دهد و هنگامی که روی آن کلیک می شود، عملکرد کنترلر مناسب را فراخوانی می کند.

برخی تصورات غلط در مورد هدف یک view وجود دارد، به خصوص در میان توسعه دهندگان وب که به تازگی شروع به ساخت برنامه های خود با استفاده از MVC کرده اند. یکی از قوانینی که اغلب نقض می شود این است نما به هیچ وجه نباید با مدل ارتباط برقرار کند، و همه داده های دریافت شده توسط view فقط باید از کنترل کننده باشد. در عمل، توسعه دهندگان اغلب این مفهوم را نادیده می گیرند، که در قلب الگوی MVC قرار دارد. مقاله Fabio Cevasco این رویکرد گیج کننده به MVC را با CakePHP، یکی از بسیاری از چارچوب های MVC غیر استاندارد، نشان می دهد:

درک این نکته بسیار مهم است که برای به دست آوردن یک معماری MVC مناسب، نباید هیچ گونه تعامل مستقیمی بین نماها و مدل ها وجود داشته باشد. تمام منطق تبادل داده بین آنها باید در کنترلرها پیاده سازی شود.

علاوه بر این، یک تصور غلط رایج وجود دارد که یک View فقط یک فایل الگو است. همانطور که تام باتلر اشاره کرد، این تصور غلط دامنه وسیعی دارد زیرا بسیاری از توسعه دهندگان از همان ابتدا ساختار MVC را اشتباه درک می کنند، پس از آن توده های توسعه دهندگان مبتدی شروع به القای بیشتر این "دانش" می کنند. در واقعیت، یک view خیلی بیشتر از یک الگو است، اما بسیاری از فریم ورک‌های مبتنی بر الگوی MVC، مفهوم یک دیدگاه را چنان تحریف کرده‌اند که هیچ‌کس اهمیتی نمی‌دهد که کاربردهای آن‌ها از نظر الگوی MVC چقدر درست است.

نکته مهم دیگر این است که view هرگز با داده های "خالص" از کنترلر کار نمی کند، یعنی کنترل کننده هرگز با view کار نمی کند و مدل را دور می زند. در فرآیند تعامل بین کنترلر و نما، مدل باید همیشه بین آنها باشد.

کنترل کننده

کنترلر آخرین قطعه از بسته نرم افزاری MVC است. وظیفه کنترلر دریافت داده از کاربر و دستکاری مدل است. این کنترل کننده است و فقط او بخشی از سیستم است که با کاربر تعامل دارد.

به طور خلاصه، کنترلر را می توان به عنوان یک جمع آوری کننده اطلاعات توصیف کرد که آن را برای پردازش و ذخیره سازی به مدل ارسال می کند. او نباید با داده ها کاری انجام دهد، بلکه فقط بتواند آنها را از کاربر دریافت کند. کنترل کننده با یک نمای و یک مدل مرتبط است، بنابراین یک جریان یک طرفه داده را سازماندهی می کند و آن را در هر مرحله کنترل می کند.

بسیار مهم است که به یاد داشته باشید که کنترلر فقط در نتیجه تعامل کاربر با view شروع به کار می کند که تابع کنترل کننده مربوطه را فراخوانی می کند. رایج ترین اشتباه در میان توسعه دهندگان این است که کنترلر به سادگی به عنوان دروازه ای بین view و مدل در نظر گرفته می شود. در نتیجه، کنترل کننده دارای آن دسته از توابعی است که باید توسط view انجام شود (به هر حال، این ایده که view فقط یک فایل الگو است از اینجا می آید). علاوه بر این، بسیاری به طور کلی تمام منطق پردازش داده ها را کنار می گذارند و فراموش می کنند که مدل در الگوی MVC برای چه چیزی در نظر گرفته شده است.

MVC در PHP

من پیشنهاد می کنم سعی کنید موارد فوق را در یک برنامه کوچک پیاده سازی کنید. بیایید با ایجاد کلاس های model، view و controller شروع کنیم:

string = "MVC + PHP = عالی!"; ))کنترلر = $controller; $this->

" . $this->model->string ."

"; } } مدل = $model; ))

کلاس های اصلی آماده است. حالا بیایید آنها را به هم پیوند دهیم و برنامه خود را اجرا کنیم:

خروجی();

همانطور که می بینید، کنترلر هیچ عملکردی ندارد زیرا کاربر به هیچ وجه با برنامه ارتباط برقرار نمی کند. همه عملکردها در نما قرار می گیرند، زیرا برنامه ما صرفاً برای نمایش داده ها است.

بیایید برنامه را با کمی تعامل گسترش دهیم تا ببینیم کنترلر چگونه کار می کند:

string = "MVC + PHP = عالی، اینجا را کلیک کنید!"; ))کنترلر = $controller; $this->model = $model; ) خروجی تابع عمومی () (return"

مدل-> رشته . "

"; } } مدل = $model; ) عملکرد عمومی clicked() ($this->model->string = «به‌روزرسانی داده‌ها، به لطف MVC و PHP!»)

و در نهایت، بیایید کد پیوند را کمی مدرن کنیم:

($_GET["عمل"])(); ) echo $view->output();

نتایج

در این مقاله کوتاه به مفاهیم اولیه الگوی طراحی MVC پرداخته ایم و یک برنامه کاربردی ساده بر اساس آن توسعه داده ایم، البته هنوز تا امکان استفاده از آن در زندگی واقعی بسیار فاصله داریم. در مقاله بعدی، مشکلات اصلی را بررسی خواهیم کرد که اگر نگاه دقیق تری به ساخت معماری اپلیکیشن بر اساس الگوی MVC داشته باشید، با آن مواجه خواهید شد. گوش به زنگ باشید!

توسعه یک برنامه مطابق با الگوی طراحی MVC (Model-View-Controller) برای جاوا معمولی است و در رابطه با DroidScript غیر قابل درک و غیر ضروری به نظر می رسد. چرا مسائل را پیچیده کنیم؟ MVC به دلیل استفاده از کلمات زیبا، اما نامفهوم (مفهوم، مدل، منطق تجاری، الگو) و نمایش های پیچیده در زمینه جاوا هنگام در نظر گرفتن هاله ای از پیچیدگی و "جادو" به دست آورد. همه چیز بسیار ساده تر است: MVC یکی از الگوهای طراحی است که در آن اضافیجداسازی کددر شی گرا محیط.

عنصر مرکزی مدل MVC کنترلر است - یک برنامه معمولی DroidScript که از آن کد مربوط به نشانه گذاری بصری و طراحی خارجی ویجت ها و همچنین داده ها و روش های دسترسی به آنها خارج می شود. با داده، ما به درک اطلاعات ذخیره شده در آرایه ها، فایل ها، پایگاه های داده عادت داریم. اما در مفهوم MVC، داده ها به معنای وسیع کلمه درک می شوند - همه چیزهایی هستند که کد برنامه نیستند:

  • داده های خارجی از فایل ها و پایگاه های داده - متادیتا، متن، گرافیک، صداها، موسیقی و غیره.
  • داده های برنامه داخلی - رشته هایی با برچسب روی دکمه ها و سایر کنترل ها، متن در کادرهای محاوره ای، توضیحات سبک، ثابت ها، گرافیک های تولید شده با برنامه و غیره.

از دیدگاه کاربر، کار او با برنامه هنگام استفاده از MVC تغییری نکرده است: او همچنین روی دکمه ها کلیک می کند، داده ها و نحوه نمایش آنها را انتخاب می کند. تغییرات ممکن است نگران کننده باشد امکاناتاین کار. و در سمت توسعه، تغییرات قابل توجه است: تعامل بین داده ها و نمایش آنها در مفهوم MVC رخ می دهد. از طریق کنترلر و تحت کنترل آن.

بیایید با یک مثال ساده از استفاده از MVC در یک برنامه یک فایل شروع کنیم.

اجرای تک فایل مدل MVC

بیایید یک برنامه ساده را در نظر بگیریم.

تابع OnStart()( var _lay = app.CreateLayout("خطی"، "VCenter,FillXY"); var _btnShowVersion = app.CreateButton("نمایش نسخه"، 0.3، 0.1)؛ _btnShowVersion.SetBackColor("9#767"); _btnShowVersion.SetMargins(0، 0.05، 0، 0); _btnShowVersion.SetOnTouch(function()( _btnShowVersion.SetText("Application Version 1.0"); )); _lay.AddChild.

در نگاه اول، همه چیز خوب به نظر می رسد، اما فرض کنید باید رنگ بندی برنامه را تغییر دهید و برچسب ها را به چندین زبان نمایش دهید. این منجر به عوارض خواهد شد، زیرا تمام داده‌های موجود در مثال نشان داده شده مقادیر ثابتی هستند (للفظی). این به طور قابل توجهی انعطاف پذیری کد را کاهش می دهد و اشکال زدایی و نگهداری آن را پیچیده می کند.

اشکال دیگر این است که داده ها - برچسب های روی دکمه، نشانه گذاری - روش های نمایش ویجت ها و عملکرد - بلوک کدی که برچسب روی دکمه را با کلیک روی آن تغییر می دهد در یک بلوک و در یک فایل قرار دارند. یعنی برای تغییر کتیبه باید این فایل را باز کنید و به کل کد اپلیکیشن دسترسی پیدا کنید. مثل این است که تعویض چرخ ماشین نیازمند جدا کردن بدنه ماشین برای دسترسی به همه چیز در داخل است. برای چی؟ در فرآیند جداسازی بدنه خودرو، می توانید به طور تصادفی چیزی را بگیرید و آن را به حالت غیرفعال برسانید. در کد نیز امکان پذیر است: من می خواستم نام خط را در یک مکان جایگزین کنم، اما جایگزینی در کل فایل رخ داد که منجر به پراکندگی خطاها شد. یا من فقط می خواستم رنگ دکمه را تغییر دهم، اما به طور تصادفی روی کد کنار آن قلاب شدم و کل برنامه از کار افتاد.

یکی از اهداف الگوی MVC دقیقاً محدود کردن دسترسی است: ابتدا ماژول (یا بلوک کد) که منبع خطا است مشخص می شود و سپس فقط دسترسی به آن داده می شود. در صورت نیاز به تعویض چرخ، چرا باید به الکترونیک و موتور خودرو دسترسی داشته باشید؟

اگر توسعه در یک فایل انجام شود، اغلب این اتفاق می افتد: توابع جدید در ابتدا یا انتهای کد در جای خود قرار می گیرند، که در نهایت منجر به مخلوط شدن آنها می شود. در اینجا ترکیب کدها را در خود توابع اضافه کنید، و در عرض یک ماه، حتی با نظرات، فهمیدن همه چیز آسان نخواهد بود.

بیایید مثال بالا را در زمینه MVC پیاده سازی کنیم. برای انجام این کار، تمام کدها باید در بلوک های مناسب تقسیم و گروه بندی شوند. ترتیب بلوک ها در کد مهم نیست، اما بهتر است به منطق پایبند باشیم: کنترل کننده برای نمایش آنها به داده ها و عناصر نیاز دارد، بنابراین در آخر قرار می گیرد. در زمان نمایش داده ها باید وجود داشته باشند. بنابراین بلوک مدل اول می شود:

  1. مدل
  2. نمایندگی
  3. کنترل کننده
//+++ مدل (function()( var _obj = ; //+++ داده var _version = "نسخه برنامه 1.0"؛ var _titleShowVersion = "نمایش نسخه"؛ //--- داده
//+++ متدهای عمومی برای دسترسی به داده _obj.getVersion = function()( return _version; ) _obj.btnGetTitle = function()( return _titleShowVersion; ) //--- متدهای عمومی برای دسترسی به داده window.model = _obj; // باز کردن دسترسی به شی محلی ))(); //--- مدل //+++ نمای (تابع ()( var _lay = app.CreateLayout("خطی"، "VCenter,FillXY")؛ var _btnShowVersion = app.CreateButton(window.model.btnGetTitle()، 0.3، 0.1)؛ _btnShowVersion.name = "_btnShowVersion"؛ _btnShowVersion.SetBackColor("#66778976")؛ _btnShowVersion.SetMargins(0، 0.05، 0، 0); _lay.y.

))(); //--- مشاهده //+++ کنترلر (تابع(p_object)( var _obj = ; // روش جستجوی شی عمومی _obj.findObjectById = تابع(p_name)( var _objectList = app.GetObjects(); برای (var _i در _objectList)( if(_objectList[_i].name == p_name)( return _objectList[ _i]; ) ) return null; ) window.control = _obj; ))(); function OnStart()( var _buttonShowVersion = window.control.findObjectById("_btnShowVersion"); //+++ action _buttonShowVersion.SetOnTouch(function()( this.SetText(window.model.getVersion()); / --- اقدام ) //--- کنترل کننده

به دلیل تفکیک توابع، کد برنامه چندین برابر شده است.

در ابتدا، همه متغیرها خصوصی می شوند و فقط در پایان، در صورت لزوم، دسترسی به آنها از طریق شی پنجره جهانی باز می شود که امکان انجام بدون متغیرهای جهانی را فراهم می کند.

مثال یک جستجوی ویجت را مانند جاوا پیاده سازی می کند، اما می توانید آن را آسان تر انجام دهید و با نمایش شی از طریق یک آرایه انجمنی جهانی، کد را کارآمدتر کنید:

Window.controls = ;
window.controls.buttonShowVersion = _btnShowVersion;

داده ها، نمایش آن و واکنش به کنش ها در بلوک های مختلف و بدون اختلاط با یکدیگر قرار دارند که کار توسعه دهنده را با آنها آسان تر می کند. هرچه کار با داده ها و کدها آسان تر باشد، خطاهای کمتری خواهند داشت، اشکال زدایی، نگهداری و مقیاس آن آسان تر است.

لازم نیست هر سه این اجزا را از یکدیگر جدا کنید. انواع مختلفی از MVC و همچنین اجرای ناقص این مدل وجود دارد. برای مثال، می‌توانید داده‌ها را جدا کنید و کد عمل را با کنترل‌ها با استفاده از تماس‌های ناشناس ترکیب کنید.

هنگام کار در یک محیط شی گرا، جداسازی کد و داده از همان ابتدا وجود دارد: داده ها و اقدامات در کلاس ها گروه بندی می شوند، اشیا از طریق روش های عمومی با یکدیگر تعامل دارند و غیره. به لطف MVC، تفکیک دقیق تر و واضح تری از کد و داده بر اساس عملکرد اصلی آنها وجود دارد.

برای درک عمیق تر از مزایای استفاده از مدل MVC، اجازه دهید کد را به فایل های جداگانه تقسیم کنیم.

پیاده سازی سه فایلی مدل MVC

جداسازی کد به فایل های مختلف برای کار راحت تر با آن استفاده می شود. تعداد زیاد فایل های کوچکی که در پروژه های MVC مشاهده می شود ممکن است این ادعا را زیر سوال ببرد، اما دیدن فایل ها یک چیز است و کار با آنها چیز دیگری است. در هر لحظه از زمان، توسعه دهنده با یک فایل از مجموعه کوچکی از آنها تعامل دارد. برای انجام این کار، شناخت درستی از ساختار سازمان پروژه و نظارت مستمر ضروری است سه فایل برتر- مدل، نمایش و کنترلر، به طوری که به طور تصادفی کد شخص ثالث را ویرایش نکنید. با توجه به محدودیت های ویرایشگر DroidScript، این گروه بندی فقط با نام فایل ها در فهرست اصلی امکان پذیر است، به عنوان مثال:

myproject_model.js - مدل
myproject_view.js - مشاهده
myproject_control.js - کنترلر

در زیر نمونه ای از تقسیم کد مثال قبلی به فایل ها آورده شده است.

myproject_model.js - مدل(تابع منبع رشته _obj.getVersion = function()( return _version; ) _obj.btnGetTitle = function()( return _titleShowVersion; ) window.model = _obj; ))(); myproject_view.js - مشاهده(تابع ()( var _lay = app.CreateLayout ("خطی"، "VCenter,FillXY")؛ var _btnShowVersion = app.CreateButton(window.model.btnGetTitle()، 0.3، 0.1)؛ _btnShowVersion.nhowS" = "_bt" ؛ _btnShowVersion.SetBackColor("#66778976")؛ _btnShowVersion.SetMargins(0, 0.05, 0, 0); _lay.AddChild(_btnShowVersion); app.AddLayout(_lay); ))(); myproject_control.js - کنترلر app.LoadScript("myproject_model.js"); app.LoadScript("myproject_view.js");(function(p_object)( var _obj = ; // روش جستجوی شی _obj.findObjectById = function(p_name)( var _objectList = app.GetObjects(); for (var _i در _objectList)( if(_objectList[_i].name = = p_name)( return _objectList[ _i]; ) ) return null; ) window.control = _obj; ))(); function OnStart()( var _buttonShowVersion = window.control.findObjectById("_btnShowVersion"); //+++ action _buttonShowVersion.SetOnTouch(function()( this.SetText(window.model.getVersion()); / --- عمل )

چنین تقسیم ساده ای از کد به فایل ها آسان نبود. برای انجام این کار، قبلاً یک ارتباط با مدل از طریق دارایی عمومی شی ریشه جهانی برقرار شد - پنجره.مدلو ارتباط با view از طریق آرایه جهانی _نقشهاز طریق روش app.GetObjects.

مزیت تقسیم کد به فایل ها این است که اکنون می توانید کد را با یک بلوک کامل جایگزین کنید، به عنوان مثال، برای راه اندازی سریع یک پروژه، پیاده سازی یک مدل ساده، و سپس فایل را با یک فایل کاربردی تر، اما با همان، جایگزین کنید. نام و رابط این رویکرد، به عنوان مثال، هنگام تعمیر تجهیزات استفاده می شود. اگر قبلاً تعمیر شامل جستجوی آهسته و پر زحمت و جایگزینی قطعات رادیویی خراب بود، اکنون بلوک های استاندارد جایگزین می شوند. هزینه تعمیر یک برد پیچیده به طور قابل توجهی بالاتر از تعویض سریع آن است.

از آنچه گفته شد، نتیجه می شود که یک رابط طراحی شده خوب می تواند ادغام بعدی ماژول ها را به طور قابل توجهی ساده کند.

در جاوا اسکریپت، اشیا با مرجع ارسال می شوند. تغییر ویژگی های یک ویجت در کنترلر، ویژگی ها را تغییر می دهد اکثرویجت از نظر تئوری، جدا کردن اشیاء مشاهده از اشیاء کد ممکن است، همانطور که در جاوا انجام می شود، جایی که ساختارهای xml به عنوان اولین مورد استفاده می شود، اما این به دو دلیل چندان منطقی نیست - عدم وجود ویرایشگر رابط بصری در DroidScript و مجموعه محدودی از ویژگی های موجود اشیاء API.

پیاده سازی چند فایلی مدل MVC

بسته به وظایف و پیچیدگی پروژه، جزئیات جداسازی کد و داده، در حالت کلی، ممکن است متفاوت باشد. علاوه بر این، می‌توانید داده‌های کاربر را از منابع جدا کنید، می‌توانید منابع را بر اساس نوع، اقدامات گروهی و غیره اصلاح کنید. اما ویرایشگر DroidScript به شما اجازه نمی‌دهد که به طور کامل با استفاده از MVC کار کنید.

مبلغ 5000 روبل

عدد (gs 8225497)

تقلید از اسکناس اصلی بانک روسیه در سال 1997

کاغذ.زیر نور UV روشن نمی شود

روش چاپچاپ افست تخت - همه تصاویر. تولید مثل رنگ مخدوش است. همه تصاویر دارای درخشندگی مشخصی هستند. توسط نقاط رنگی تشکیل شده است. در محل های انحراف، ریزش مواد رنگی مشاهده می شود.

علائم حفاظت عمومی مقابل

واترمارک (1،2)


تقلید با چاپ روی یک ماده سفید در سمت جلو. تصاویر واترمارک تحریف شده در نور منعکس شده مشاهده می شوند

تصویر پنهان (اثر کیپ) (3)


تکثیر نشده است

الیاف محافظ

چاپ روی چاپ تقلیدی در اشعه ماوراء بنفش درخششی از رنگ های سبز و قرمز مشاهده می شود.

رنگ تغییر رنگ (4)


تصویر نشان از درخشندگی افزایش یافته است. اثر OVI بازتولید نشد

عنصر MVC+(5).


تقلید نشده حاشیه های Moiré اثر MVC در هر زاویه دید مشاهده می شود. هنگام کپی کردن از نسخه اصلی نمایش داده می شود.

میکروپرفوراسیون (6)


شبیه سازی شده. ریز سوراخ‌های قابل مشاهده در نور بازتابی

لاک تغییر رنگ (7)

نشان بانک روسیه با رنگ طلایی پوشانده شده است. اثر پلاریزاسیون بازتولید نمی شود.

منبت بی رنگ (8)

تقلید نشده

تسکین

تقلید نشده

مبلغ 5000 روبل

عدد (gs 8225497)

تقلید از اسکناس اصلی بانک روسیه مدل 1997.

علائم حفاظت عمومی سمت معکوس

ریزمتن (9،10)


تا حدی تکثیر شده است

موضوع امنیتی (11)


تقلید با یک ماده سفید در سمت جلو، خروجی ها با مهر و موم فویل تقلید شده است. خروجی های رشته امنیتی به سختی قابل تشخیص هستند.

ویژگی های امنیتی قابل خواندن از طریق ماشین

حفاظت نورانی

تقلید جزئی

حفاظت IR

تقلید جزئی

حفاظت مغناطیسی

تقلید نشده

توجه داشته باشید. به گفته آژانس های اجرای قانون فدراسیون روسیه، یک اسکناس تقلبی در قلمرو پرم کشف و ضبط شد.

مواد آماده شد IPK "InterCrim-press".

برترین مقالات مرتبط