برنامه نویسی و طراحی وب

MVC چیست و چه کاربردی در برنامه نویسی دارد؟

معماری MVC در برنامه‌نویسی چیست و چرا باید از آن استفاده کنیم؟

MVC چیست؟

MVC یک الگوی معماری نرم‌افزار است که مخفف کلمات ModelViewController است. این سه بخش نرم‌افزای که مستقل از هم هستند، همیشه باهم در ارتباط هستند. در حقیقت Model وظیفه ارتباط با پایگاه داده را برعهده دارد. نقش View، نمایش اطلاعات برای کاربر است و Controller رابط بین Model و View است.

معماری نرم افزاری ام‌وی‌سی، یک برنامه کاربردی را به سه جزء اصلی تقسیم می کند:

Model: مسئول مدیریت داده ها و ارتباط با پایگاه داده است.

View: مسئول ارائه داده ها است و داده‌ها را برای کاربر نمایش می‌دهد یا تعاملات کاربر را مدیریت می‌کند.

Controller: مسئول دریافت و پردازش ورودی های کاربر است. به عبارتی، واسطی است بین دو جزء ویو و مدل.

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

یک مثال از MVC در دنیای واقعی

به عنوان مثال فرض کنید یک رستوران مدرن داریم که توسط ربات ها مدیریت میشه. حالا چندنفر هم واسه ناهار به رستوران مراجعه میکنند.

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

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

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

در این مثال نتیجه میگیریم که هر کدام از این اجزا در حال انجام کار خود به طور مستقل هستند بدون اینکه در کار یکدیگر دخالت کنند.

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

حالا فرض میکنیم همین فرآیند را در یک وب‌سایت داریم. پس با من همراه باشید تا این فرآیند را به صورت واقعی در یک سایت بررسی کنیم. با دیدن تصویر زیر قضیه برای شما روشن خواهد شد:

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

حالا میخوام Model-View-Controller رو به صورت مجزا براتون توضیح بدم.

Model چیست؟

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

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

وظایف اصلی بخش Model:

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

نکته بسیار مهم این است که همانطور که کنترلر به هیچ وجه با پایگاه داده‌ها ارتباط مستقیم ندارد، مدل هم با بخش View هیچ ارتباط مستقیمی برقرار نمی‌کند.

View چیست؟

ویو در معماری MVC وظیفه ارائه داده‌ها به کاربر و همچنین پردازش ورودی های کاربر را بر عهده دارد. همانطور که از نامش پیداست، View یا همان نما (نمایش) مسئول رابط کاربری یک برنامه کاربردی است. داده‌هایی را که از Controller دریافت می‌شود را در قالب یک الگوی HTML برای مرورگر تولید می کند.

مدل و ویو با هم ارتباط مستقیم ندارند. در واقع کنترلر، با درخواست اطلاعات از مدل، داده‌های جمع‌آوری شده را به دست View می‌رساند.

وظایف اصلی بخش View:

  • دریافت اطلاعات لازم از کنترلر
  • ایجاد رابط کاربری برای برنامه و آماده سازی آن برای مرورگر

توجه به این نکته مهم است که View نباید هیچ داده ای را پردازش کند، زیرا این کار باید توسط کنترلر انجام شود.

Controller چیست؟

کنترلر در معماری MVC مسئول کنترل منطق برنامه است و به عنوان هماهنگ کننده بین View و Model عمل می‌کند و درخواست‌های URL را از طریق View از کاربر دریافت و مدیریت می‌کند، سپس داده های کاربر را با کمک Model پردازش می‌کند و نتایج را به View ارسال می کند. به زبان ساده تر، مؤلفه Controller مسئول کنترل نحوه تعامل کاربر با یک برنامه MVC است.

وظایف اصلی بخش Controller:

  • دریافت درخواست‌ها از ویو یا کاربران و انتقال آن به مدل، سپس دریافت پاسخ و اطلاعات لازم از مدل و انتقال آن به ویو
  • مدیریت و پردازش داده‌های دریافت شده

کدام فریمورک ها از معماری MVC استفاده می‌کنند؟

در اینجا لیستی از فریمورک های محبوبی که از الگوی طراحی Model-View-Controller (MVC) استفاده می‌کنند، آمده است:

  • Ruby on Rails (Ruby)
  • Django (Python)
  • ASP.NET (C#)
  • Laravel (PHP)
  • Express (JavaScript/Node.js)
  • Spring (Java)
  • CakePHP (PHP)
  • Yii (PHP)
  • CodeIgniter (PHP)
  • Ember.js (JavaScript)

معرفی برخی از الگوهای معماری نرم‌افزاری

  • (MVC) Model-View-Controller: الگوی اصلی MVC است که توسط تریگو رینسکویگ در اواخر دهه 1970 به‌وجود آمده و معمولا در توسعه وب استفاده می شود.
  • (HMVC) Hierarchical Model-View-Controller:‌ معماری سلسله مراتبی MVC که در توسعه وب استفاده می‌شود. « HMVC چیست؟ »
  • Model-View-Presenter (MVP): گونه ای از MVC که معمولاً در برنامه های دسکتاپ استفاده می‌شود.
  • Model-View-ViewModel (MVVM): نوعی از MVC که معمولاً در برنامه های دسکتاپ و موبایل استفاده می‌شود.
  • Model–view–adapter (MVA): یک الگوی معماری نرم افزاری و معماری چند لایه است که می‌تواند در نرم‌افزار های مختلف استفاده شود. اما نسبت به سایر الگوهای ذکر شده، کمتر استفاده می‌شود.

مثال ساده پیاده ‌سازی MVC با PHP

حالا میخوام یه مثال ساده با کد PHP بنویسم که در این مثال از روش ام‌وی‌سی استفاده شده. یعنی برنامه به سه قسمت «مدل» – «ویو» – «کنترلر» تقسیم میشه:

ابتدا کد زیر را در قسمت Model قرار می‌دهیم: ( فایل User.php )

class User {
    private $name;

    public function setName($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

در کد بالا کلاسی به نام User داریم که دارای دو متد setter و getter است. با قسمت setter می‌توانیم یک نام را ست کنیم و در قسمت getter می‌توانیم آن نام را دریافت کنیم.

در قسمت View کد زیر را قرار می‌دهیم: ( فایل view.php )

<html>
<body>
    <h1>Hello, <?php echo $user->getName(); ?></h1>
</body>
</html>

در کد بالا با استفاده از متد getName نام را دریافت می‌کنیم و در تگ h1 کد های html قرار می‌دهیم تا کاربر بتواند آن نام را در مرورگر خود دریافت کند.

در قسمت Controller کد زیر را قرار می‌دهیم:

require_once 'User.php';

$user = new User();
$user->setName('Reza Bazyar');

require_once 'view.php';

همانطور که در بالا گفته بودم، «کنترلر» یک واسط میان «مدل» و «ویو» است. در کد بالا ابتدا ویو را از فایل User.php فراخوانی می‌کند. سپس یک شئ از کلاس User ایجاد کرده و در متغیر $user می‌ریزد. حالا متد setName را روی user صدا می‌زند و نام Reza Bazyar را به آن می‌دهد. در نهایت ویو را از فایل view.php فراخوانی می‌کند.

پس با توجه به اینکه در کنترلر نام Reza Bazyar ست شده است و در قسمت view با استفاده از متد getName آن را چاپ می‌کند، باید این نام در صفحه مرورگر ما چاپ شود.

مشاهده پروژه ساده mvc در گیت‌هاب


مثال پیاده ‌سازی MVC با PHP

حالا میخوام یک مثال دیگر این معماری با استفاده از کد PHP برای شما عزیزان بنویسم. این مثال کمی به زندگی واقعی ما نزدیکتر است و سعی میکنم آن را سخت‌تر کنم.

ابتدا کد زیر را به عنوان Entity در یک فایل قرار می‌دهیم : ( فایل Task.php )

class Task
{
    private $id;
    private $name;
    private $description;
    private $dueDate;
    private $completed;

    public function __construct($id, $name, $description, $dueDate, $completed)
    {
        $this->id = $id;
        $this->name = $name;
        $this->description = $description;
        $this->dueDate = $dueDate;
        $this->completed = $completed;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function getDescription()
    {
        return $this->description;
    }

    public function getDueDate()
    {
        return $this->dueDate;
    }

    public function isCompleted()
    {
        return $this->completed;
    }

    public function setCompleted($completed)
    {
        $this->completed = $completed;
    }
}

کلاس Task در task.php ویژگی‌هایی (properties) را برای یک کار تعریف می کند، مانند id, name, description, dueDate, completed. همچنین گیرنده‌ها (setters) و تنظیم‌کننده‌ها (getters) را برای این ویژگی‌ها (properties) فراهم می کند. این کلاس برای نمایش یک کار در برنامه کاربردی و برای تعامل با داده های ذخیره شده در پایگاه داده استفاده می شود.

حالا کد زیر را در قسمت Model قرار می‌دهیم: ( فایل TaskModel.php )

class TaskModel
{
    private $tasks = array();

    public function __construct()
    {
        $this->tasks[] = new Task(1, 'Buy groceries', 'Buy milk, bread, and eggs', '2023-02-04', false);
        $this->tasks[] = new Task(2, 'Write a report', 'Write a report on the latest market trends', '2023-02-06', false);
        $this->tasks[] = new Task(3, 'Attend meeting', 'Attend a meeting with the team at 10 AM', '2023-02-03', true);
    }

    public function getTasks()
    {
        // Code to retrieve all the tasks from the database
        return $this->tasks;
    }

    public function getTaskById($id)
    {
        // Code to retrieve a task from the database using the $id
        foreach ($this->tasks as $task) {
            if ($task->getId() == $id) {
                return $task;
            }
        }
        return null;
    }

    public function updateTask(Task $task)
    {
        // Code to update the task in the database
    }

    public function deleteTask(Task $task)
    {
        // Code to delete the task from the database
    }
}

همانطور که در بالا توضیح داده بودم، مدل در معماری MVC مسئول تعامل با پایگاه داده برای انجام عملیات CRUD (ایجاد، خواندن، به‌روز رسانی، حذف) بر روی داده‌ها است.

کلاس TaskModel در TaskModel.php روش هایی را برای انجام این عملیات ارائه می دهد، مانند getTaskById، getTasks، updateTask و deleteTask. این متدها، اطلاعات را از پایگاه داده می‌گیرند و روی آنها را اصلاح می‌کنند. در حالی که کلاس Entity (در این مورد، کلاس Task) ساختار داده‌های ذخیره شده را تعریف می‌کند.

سپس کد زیر را در قسمت View قرار می‌دهیم: (فایل view.php )

<html>

<head>
    <title>Task Manager</title>
</head>

<body>
    <h1>Task Manager</h1>
    <table>
        <tr>
            <th>Task Name</th>
            <th>Description</th>
            <th>Due Date</th>
            <th>Status</th>
        </tr>
        <?php foreach ($tasks as $task) : ?>
            <tr>
                <td><?php echo $task->getName(); ?></td>
                <td><?php echo $task->getDescription(); ?></td>
                <td><?php echo $task->getDueDate(); ?></td>
                <td><?php echo $task->isCompleted() ? 'Completed' : 'Pending'; ?></td>
            </tr>
        <?php endforeach; ?>
    </table>
</body>

</html>

همانطور که قبلا در بالا توضیح داده بودم، کلاس View وظیفه نمایش داده ها به کاربر را بر عهده دارد. «ویو» وظیفه دارد که اطلاعات را از Controller دریافت کند و در قالب HTML به کاربر نمایش دهد.

در نهایت کد زیر را در قسمت Controller قرار می‌دهیم: ( فایل Controller.php )

require_once 'Task.php';
require_once 'TaskModel.php';

class TaskController
{
    private $model;

    public function __construct()
    {
        $this->model = new TaskModel();
    }

    public function updateTask()
    {
        $taskId = $_GET['id'];
        $task = $this->model->getTaskById($taskId);

        if ($task != null && !$task->isCompleted()) {
            $task->setCompleted(true);
            // Update the task in the database
        }
    }

    public function showTasks()
    {
        $tasks = $this->model->getTasks();
        require_once 'view.php';
    }
}

$controller = new TaskController();
if (isset($_GET['id'])) {
    $controller->updateTask();
}
$controller->showTasks();

در کنترلر، دو خط اول به دو فایل PHP به نام های Task.php و TaskModel.php نیاز دارند که به ترتیب کلاس Task و کلاس TaskModel را تعریف می‌کنند.

در ادامه کلاس TaskController تعریف می‌شود که دو ویژگی (متد) عمومی updateTask و showTasks را دارد.

سازنده (construct) کلاس TaskController یک شی TaskModel جدید ایجاد می‌کند و آن را در خصوصیت (پراپرتی) $model ذخیره می کند.

متد updateTask شناسه کاری را که قرار است به روز شود از آرایه $_GET بازیابی می کند و از شئ TaskModel برای بازیابی شی Task مربوطه استفاده می کند. اگر کار وجود داشته باشد و قبلاً تکمیل نشده باشد، وضعیت تکمیل کار را روی true تنظیم می‌کند.

متد showTasks تمام وظایف را از پایگاه داده با استفاده از شئ TaskModel بازیابی می‌کند و سپس «ویو» (view.php) را برای نمایش وظایف فراخوانی می‌کند.

سپس یک شی TaskController جدید ایجاد می کند و اگر پارامتر id در آرایه $_GET وجود داشته باشد، متد updateTask آن را فراخوانی می کند و سپس متد showTasks آن را فراخوانی می کند تا همه وظایف نمایش داده شود.

در نهایت می‌توانیم نتیجه کد ها را در مرورگر خود مشاهده کنیم.

مشاهده پروژه تسک منیجر در گیت‌هاب

مزایا و معایب معماری MVC در برنامه نویسی

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

مزایای معماری MVC در برنامه نویسی

  • منطق اصلی برنامه (یعنی همان منطق تجاری آن) از منطق رابط کاربری مجزا است.
  • تکرار کد ها را کمتر می‌کند و در نهایت تمام اجزا قابل استفاده مجدد هستند.
  • به ایجاد یک ساختار یکدست و استوار در اپلیکیشن کمک می‌کند.
  • برنامه ما خواناتر می‌شود و در نتیجه نگهداری این نوع برنامه‌ها آسان‌تر است.
  • هر بخش معماری MVC این قابلیت را دارد که به صورت مستقل ذخیره‌سازی شود.
  • در این معماری تست اجزای مختلف برنامه بی‌دردسرتر است.

معایب معماری MVC در برنامه نویسی

  • معماری MVC برنامه را کمی پیچیده می‌کند و درک آن سخت است.
  • برای برنامه‌های کوچک مناسب نیست زیرا تأثیر نامطلوبی در عملکرد و طراحی آن برنامه دارد.
  • گاهی اوقات عدم دسترسی View به داده‌ها، کاربرد آن را کاهش می‌دهد.
  • برای دستیابی به فرم های پیچیده تر استفاده از JavaScript/AJAX لازم است.

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

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

نتیجه گیری:

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

سیدرضا بازیار

من مهندس فناوری اطلاعات و توسعه دهنده Back end هستم. حس کنجکاوی، تمایل به کشف دنیاهای جدید و علاقه زیادی به حل چالش‌های گوناگون در زمینه‌های مختلف داشتم باعث شد وارد حرفه‌ی پرچالش و عمیق برنامه‌نویسی بشوم و هر روز بیشتر در این دنیای بزرگ غرق می‌شوم. در حال حاضر با مهارت هایی نرم مانند کار تیمی، قدرت مذاکره، خوش برخوردی، پرورش ایده و مهارت های سخت مانند PHP, OOP, Clean Code, Design Patterns و ... با علاقه مشغول به فعالیت در جامعه متن‌باز هستم. معتقدم هر روز بیشتر از دیروز، عمده کارهای انسان‌ها توسط ربات‌ها انجام خواهد شد، به همین دلیل سعی میکنم اسکریپت‌های زیادی با PHP ، Shell Scripting و Bash Scripting بنویسم و سعی می‌کنم کارهایی که برای انسان‌ها سخت و زمانبر هستند،‌ با ربات‌ها در سریعترین زمان و کمترین هزینه ممکن انجام بدهم. در این مسیر با زبان‌های برنامه نویسی مانند C++ و پایتون هم کمی کار کرده‌ام و با سیستم های مدیریت محتوای زیادی مانند وردپرس، جوملا، ویبولتین و... هم به صورت حرفه‌ای درگیر بوده‌ام. گهگاهی سعی میکنم ربات‌هایی طراحی کنم که اطلاعات عظیمی را از طریق اسکرپینگ به دیتابیس های مختلف منتقل میکنند و از طریق API در پلتفرم های مختلف پردازش می‌شوند. در 10 سال گذشته سابقه زیادی در طراحی سایت و فروشگاه‌های اینترنتی، سئو و بهینه سازی، تست امنیت وب‌سایت‌ها، دیجیتال مارکتینگ و... داشته‌ام. خوشحال میشم بتونم تجربیات خودم رو از طریق این وبلاگ در اختیار همه شما عزیزان قرار بدهم.

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

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *