معماری mvp اندروید

راهنمای کامل معماری MVP در اندروید + یک پروژه ساده

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

معماری MVP در android

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


معرفی معماری MVP

معماری MVP (مخفف Model View Presenter) یکی از دیزاین پترن های معروف و پر استفاده ای است که در برنامه نویسی اندروید از آن استفاده میشود. همانطور که از اسم این معماری مشخص است، دارای سه لایه مختلف Model، View و Presenter است که در ادامه آنها را بصورت کامل بررسی میکنیم. اما قبل از آن با خود معماری MVP بیشتر آشنا میشویم.

معرفی معماری mvp

معماری MVP در حقیقت یکی از مشتقات معماری MVC است و بیشتر برای ساخت رابط کاربری از آن استفاده میشود. به کار بردن این معماری باعث افزایش تست پذیری نرم افزار و راحت تر شدن توسعه و نگهداری آن در آینده میشود. معماری MVP یک راه حل برای مشکلاتی که در MVC وجود داشت ارائه میدهد و میتواند اجزای اپلیکیشن را بیشتر از هم جدا کند. لایه های مختلف این معماری:

  1. لایه Model: این لایه همه داده های اپلیکیشن را درون کلاس های ساده نگهداری میکند. همه دیتایی که در نرم افزار ما استفاده میشود باید در لایه Model مدیریت شود. مانند داده هایی که از شبکه، دیتابیس، حافظه های مختلف و منابع دیگر می آیند. در حقیقت فرق زیادی بین لایه Model در این معماری و MVC وجود ندارد. وظیفه لایه Model بصورت کلی استفاده از API، کش کردن داده ها، مدیریت دیتابیس و غیره است.
  2. لایه View: این لایه شامل همه اجزای سازنده رابط کاربری اپلیکیشن ما است. یعنی همه اکتیویتی ها و فرگمنت ها در لایه View قرار میگیرند. وظیفه این لایه نمایش داده های مختلف و تغییرات آن ها به کاربر است. در معماری MVP، لایه View بصورت مستقیم با لایه Presenter در ارتباط است. یعنی همه اکشن های کاربر را به اطلاع Presenter میرساند و از همان لایه دستور میگیرد که چه داده هایی را باید به کاربر نمایش بدهد.
  3. لایه Presenter: لایه Presenter در این معماری واسط بین لایه های View و Model است. یعنی لایه View همه اتفاقات را به این لایه خبر میدهد و از آن دستور میگیرد که چه داده هایی را باید نمایش بدهد. از طرفی هم لایه Presenter به لایه View دستور میدهد که کدام داده ها را باید ذخیره کند و چه داده هایی را باید در اختیار آن قرار بدهد. در این معماری، لایه Presenter برای اتفاقاتی که در جواب تعاملات کاربر رخ میدهد (یعنی در لایه View) تصمیم گیری میکند.
معماری mvp

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

پس داده ها چگونه بین این کامپوننت ها جریان دارند؟ دیاگرام زیر این جریان را نشان میدهد:

دیاگرام جریان داده در معماری mvp

سناریو معماری MVP

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

سناریو

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


چرا باید از معماری MVP استفاده کنیم؟

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

چرا باید از mvp استفاده کنیم

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

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


مزایای معماری MVP

مزایای معماری mvp

مزایایی که با پیاده سازی معماری MVP (یا معماری های مشابه مانند MVC، MVVM، MVVC) در پروژه به وجو می آیند این موارد هستند:

  • جداسازی واضح مسئولیت ها بین کامپوننت های مختلف. این جداسازی باعث درک بهتر کدها و نگهداری راحت تر آنها میشود.
  • ماژولار شدن پروژه. ماژولار بودن به ما اجازه میدهد که مثلا پیاده سازی لایه View را به کلی تغییر بدهیم و رابط کاربری اپلیکیشن را تعویض کنیم، بدون اینکه به بقیه قسمت های اپلیکیشن کاری داشته باشیم.
  • تست پذیری راحت تر. از آنجایی که مرز های مشخصی بین کامپوننت های مختلف وجود دارد، تست کردن هر کامپوننت بصورت ایزوله راحت تر میشود (مثلا با Mock کردن بقیه کامپوننت ها).

معایب معماری MVP

معایب معماری mvp

یکی از ریسک هایی که هنگام استفاده از معماری MVP وجود دارد، این است که معمولا فراموش میکنیم که Presenter همیشه به لایه View چسبیده است. لایه View هم معمولا یک اکتیویتی است، پس اتفاقات زیر ممکن است رخ بدهد:

  1. اکتیویتی میتواند در تسک هایی طولانی Leak شود.
  2. ممکن است اقدام به آپدیت اکتیویتی هایی کنیم که قبلا از بین رفته اند.

برای نکته اول، اگر مطمئن باشید که تسک های پس زمینه شما در مدت زمانی کوتاهی تمام میشوند نگرانی زیادی وجود نخواهد داشت. اما دومین مورد شاید دردسر های بیشتری ایجاد کند. یعنی فرض کنید یک درخواست به سرور فرستادید که 10 ثانیه طول میکشد تا کامل شود و کاربر در ثانیه 5 اکتیویتی را ببندد. این مسئله باعث Crash شدن اپلیکیشن میشود. راه حل این مسئله از بین بردن همه تسک های پس زمینه در مرحله onDestroy است.


تفاوت MVP و MVC

تفاوت معماری mvp و معماری mvc

تفاوتی که بین معماری MVP و MVC وجود دارد این است که به جای مدیریت کردن هر دو لایه Controller و View درون کلاس های اکتیویتی مانند چیزی که در معماری MVC دیدیم، در این معماری لایه های View و Presenter کاملا از هم جدا هستند و هر دو این لایه سبک تر از قبل شده اند.


پیاده سازی معماری MVP در اندروید

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

پیاده سازی معماری mvp در اندروید

پیاده سازی لایه Presenter

یک فایل به اسم MainActivityPresenter.java در پروژه درست میکنیم که به عنوان واسط بین View و Model نقش ایفا میکند. یعنی به اکشن های کاربر گوش میدهد و بر اساس آنها لایه های View و Model را بروز رسانی میکند. لایه Presenter نباید از وجود لایه View با خبر باشد و برای برقراری ارتباط بین این دو لایه، از اینترفیس استفاده میشود.

public class MainActivityPresenter {

    private User user;
    private View view;

    public MainActivityPresenter(View view) {
        this.user = new User();
        this.view = view;
    }

    public void updateFullName(String fullName){
        user.setFullName(fullName);
        view.updateUserInfoTextView(user.toString());

    }

    public void updateEmail(String email){
        user.setEmail(email);
        view.updateUserInfoTextView(user.toString());

    }

    public interface View{

        void updateUserInfoTextView(String info);
        void showProgressBar();
        void hideProgressBar();

    }
}

پیاده سازی لایه Model

همانطور که گفته شد کلاس هایی که نگه دارنده داده های اپلیکیشن هستند درون لایه Model قرار میگیرند. یک فایل به اسم User.java در پروژه خودمان درست میکنیم. این فایل همه اطلاعات کاربر را درون خود نگهداری میکند.

public class User {

    private String fullName = "", email = "";

    public User() {
    }

    public User(String fullName, String email) {
        this.fullName = fullName;
        this.email = email;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Email : " + email + "\nFullName : " + fullName;
    }
}

پیاده سازی لایه View

این لایه مسئول نمایش رابط کاربری است و معمولا از اکتیویتی و فرگمنت تشکیل میشود. به همین دلیل یک فایل به اسم MainActivity.java به همراه فایل Layout آن را به پروژه اضافه میکنیم (برای ساخت اکتیویتی هم میتونین به مقاله اکتیویتی ها مراجعه کنید). لایه View در معماری MVP باید یک ارجاع به لایه Presenter را درون خود نگهداری کند. تنها کاری که این لایه باید انجام بدهد اطلاع دادن اکشن های کاربر به Presenter است.

اولین کاری که باید در لایه View انجام بدهیم، implement کردن MainActivityPresenter.java است. زیرا باید متد های این لایه را با هر اکشن کاربر فراخوانی کنیم. دومین کار، ساخت آبجکت MainActivityPresenter است که باید یک آبجکت از View هم به متد سازنده آن پاس بدهیم. این آبجکت همان لایه Presenter است که باید اکشن های کاربر را بررسی کند و بتواند لایه های Model و View را به روز رسانی نماید.

public class MainActivity extends AppCompatActivity implements MainActivityPresenter.View {

    private MainActivityPresenter presenter;
    private TextView myTextView;
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        presenter = new MainActivityPresenter(this);

        myTextView = findViewById(R.id.myTextView);
        EditText userName = findViewById(R.id.username);
        EditText email = findViewById(R.id.email);
        initProgressBar();


        userName.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                presenter.updateFullName(s.toString());
            }

            @Override
            public void afterTextChanged(Editable s) {
                hideProgressBar();
            }
        });

        email.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                presenter.updateEmail(s.toString());
            }

            @Override
            public void afterTextChanged(Editable s) {
                hideProgressBar();
            }
        });

    }

    private void initProgressBar() {
        progressBar = new ProgressBar(this, null, android.R.attr.progressBarStyleSmall);
        progressBar.setIndeterminate(true);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(Resources.getSystem().getDisplayMetrics().widthPixels,
                250);
        params.addRule(RelativeLayout.CENTER_IN_PARENT);
        this.addContentView(progressBar, params);
        showProgressBar();
    }

    @Override
    public void updateUserInfoTextView(String info) {
        myTextView.setText(info);
    }

    @Override
    public void showProgressBar() {
        progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideProgressBar() {
        progressBar.setVisibility(View.INVISIBLE);
    }
}

نتیجه گیری

نتیجه گیری

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


سوالی دارید؟

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


منابع بیشتر برای مطالعه

میتوانید از منابع زیر برای مطالعه بیشتر درباره معماری MVP استفاده کنید:

4 دیدگاه دربارهٔ «راهنمای کامل معماری MVP در اندروید + یک پروژه ساده»

  1. خداییش خیلی روون و خوب توضیح میدید من مقاله mvc شما رو هم خوندم ولی بازم فرق این دوتا رو کامل درک نکردم.میشه بیشتر و با تمرکز بر کدهای خودتون یک شفاف سازی کنید؟ تشکر

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

  2. بازتاب: معرفی کامل معماری MVVM در اندروید + روش پیاده سازی | برنامه چی | Barnamechi

  3. بازتاب: انواع دیزاین پترن (الگوی طراحی) در اندروید | برنامه چی | Barnamechi

دیدگاه‌ خود را بنویسید

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

اسکرول به بالا