1. 程式人生 > >MVP、MVVM,MVC設計模式的例項分析

MVP、MVVM,MVC設計模式的例項分析

先只考慮V和P的分離,在這裡,我們用介面實現
首先,程式先例項化V,主函式程式碼如下

    static class Program
    {
        /// <summary>
        /// 應用程式的主入口點。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false
); Application.Run(new FrmTestMvp()); } }

然後,我們讓V去例項化P,將對自己的引用傳給P
VIEW程式碼如下

    public partial class FrmTestMvp : Form, ITestMvpView
    {
        private TestMvpPresenter _testMvpPresenter;

        public FrmTestMvp()
        {
            InitializeComponent();
            //注意構造Presenter時需把自身傳過去
this._testMvpPresenter = new TestMvpPresenter(this); } //單擊按鈕事件 private void button1_Click(object sender, EventArgs e) { if (Click != null) { Click(); } } #region ITestMvpView 成員 //實現介面屬性方法
public TextBox TextBox1 { get { return this.textBox1; } } //委託事件 public new event Button1_Click Click; #endregion }

VIEW實現瞭如下介面。這讓我們的Presenter可以支援多個VIEW,只要他作出了對介面的實現

    //聲明瞭一個委託型別,並在介面安上了和這個委託型別相關的事件
    public delegate void Button1_Click();

    interface ITestMvpView
    {
        //宣告控制元件
        TextBox TextBox1{get;}
        //事件
        event Button1_Click Click;
    }

最後就是我們的Presenter部分,利用介面給它的介面來訪問介面。

    class TestMvpPresenter
    {
        private ITestMvpView _testMvpView;

        /// <summary>
        /// 建構函式,出入檢視介面
        /// </summary>
        /// <param name="testMvpView">ITestMvpView介面</param>
        public TestMvpPresenter(ITestMvpView testMvpView) 
        {
            this._testMvpView = testMvpView;
            this.InitEvent();
        }

        //載入委託事件
        private void InitEvent() 
        {
            this._testMvpView.Click += new Button1_Click(_testMvpView_Click);
        }

        //處理事件
        void _testMvpView_Click()
        {
            if (CheckValue())
            {
                this.ShowMessage(this._testMvpView.TextBox1.Text);
            }
            else
            {
                this.ShowMessage("輸入的值不能為空!");
                this._testMvpView.TextBox1.Focus();
            }           
        }

        //檢查TestBox1的輸入值是否合法
        private bool CheckValue()
        {
            if (this._testMvpView.TextBox1.Text.ToString() == "") 
            {
                return false;
            }
            return true;
        }

        private void ShowMessage(string message) 
        {
            MessageBox.Show(message);
        }
    }

實際上,上面的例子是先初始化view,然後初始化presenter的方式,我們成為view-first。反過來當然也一樣,叫做presenter-first方式。
另外一個例子,首先,在來看我們的Model,model是一個只包含屬性的實體類.書寫如下

    public class TestMvpModel
    {
        public string Name { get; set; }
    }

然後寫我們的view類
View類中依賴model,並負責model和view的繫結

   public partial class FrmTestMvp : Form
    {
        private TestMvpModel model;
        public TestMvpModel Model
        {
            get
            {
                return model as TestMvpModel;
            }
            set
            {
                model = value as TestMvpModel;
                label1.Text = model.Name;
            }
        }

        public FrmTestMvp()
        {
            InitializeComponent();
        }

        public EventHandler ButtonClick;

        private void button1_Click(object sender, EventArgs e)
        {
            if (ButtonClick != null)
            {
                ButtonClick(sender,e);
            }
        }
    }

最後寫我們的presenter,負責一切的初始化,和頁面邏輯的控制

 class TestMvpPresenter
    {
        public FrmTestMvp View { get; set; }
        public TestMvpPresenter(FrmTestMvp view)
        {
            this.View = view;

            this.View.Model = new TestMvpModel() {Name = "GDL" };

            this.View.ButtonClick += delegate
            {
                this.View.Model = new TestMvpModel() { Name = "ABC" };
            };
        }

    }

主程式改為如下

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            TestMvpPresenter presenter = new TestMvpPresenter(new FrmTestMvp());
            Application.Run(presenter.View);
        }

在我的理解中,MVP模式的核心就是將傳統VIEW中相互耦合的業務邏輯,頁面靜態部分,和頁面中動態部分分開。頁面中不變的靜態部分繼續放在view裡。動態部分放在model裡。而業務邏輯放在我們的presenter中。
是不是覺得上面的view程式碼有點多,還需要手工繫結兩件事:
(1)頁面動作和presenter中的處理函式

        private void button1_Click(object sender, EventArgs e)
        {
            if (ButtonClick != null)
            {
                ButtonClick(sender,e);
            }
        }

(2)模型和頁面的一致性變化

        public TestMvpModel Model
        {
            get
            {
                return model as TestMvpModel;
            }
            set
            {
                model = value as TestMvpModel;
                label1.Text = model.Name;
            }
        }

所以,微軟又推出了WPF。我們來看一下WPF中的view典型寫法

<Window x:Class="MVPDemo2.PanelView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="PanelView" Height="300" Width="300">
    <Grid>
        <Label Height="28" HorizontalAlignment="Left" Margin="10,10,0,0" Name="label1" VerticalAlignment="Top" Width="120" Content="{Binding Name}" />
        <Button Height="24" HorizontalAlignment="Left" Margin="10,79,0,0" Name="btnModify" VerticalAlignment="Top" Width="111" Click="btnModify_Click">修改Label的文字</Button>
    </Grid>
</Window>

顯然,在上述的XAML中,已經對前文提到的兩件事進行了繫結。在wpf下,我們可以輕鬆的寫出model程式碼(#region部分為INotifyPropertyChanged
介面新增)

    public class PanelPresenterationModel : INotifyPropertyChanged
    {
        private string name;

        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                if (this.name != value)
                {
                    this.name = value;
                    this.OnPropertyChanged("Name");
                }
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler Handler = PropertyChanged;
            if (Handler != null) Handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }

我們給出presenter程式碼

    public class PanelPresenter
    {
        public PanelPresenter(PanelView view)
        {
            this.View = view;

            //初始化Model
            this.View.Model = new PanelPresenterationModel() { Name = "Bao, Jianqiang" };

            this.View.ButtonClick += delegate
            {
                this.View.Model.Name = "Jax.Bao";

            };
        }

        public PanelView View { get; set; }
    }

我們看到WPF很成功的實現了MVP。

然而,還有好事者,他們開發了MVVM模式
Simple Mvvm,Mvvm Light和Prism都是MVVM的開源框架
下面只貼上典型的viewmodel的例項

namespace SilverlightApplication2.ViewModels
{
    public class StudentViewModel : NotificationObject
    {
        public StudentViewModel()
        {
            student = new Student();
        }

        Student student;
        public Student Student 
        {
            get
            {
                return this.student;
            }
            private set
            {
                this.student = value;
                this.RaisePropertyChanged(() => this.student);
            }
        }
        public bool CanSubmit
        {
            get
            {
                return true;
            }
        }

        public void Submit()
        {
            student.Mock();
        }
    }
}

在上程式碼中可以看見,viewmodel又負責處理view內容的更新,同時也負責對model內容進行同步調整。下面展現了一個一般MVVM系統的架構
這裡寫圖片描述

下面,我們用一個圖來解釋MVC
這裡寫圖片描述
MVC架構和MVP架構的區別
這裡寫圖片描述