WindowsFormsアプリでのMVPパターンサンプル

以下は、WindowsFormsアプリでMVCパターンを実装するための簡単なサンプルです

MVPとは

MVPは、MVCに似たデザインパターンで、ModelとViewを分離し、Presenterを介して連携することで、アプリケーションの保守性や拡張性を向上することを目的とします。Presenterは、Viewからの入力を処理し、Modelからのデータを受け取ってViewを更新する役割を担います。

クラス図

サンプル概要

この例では、Modelクラスでカウンターの値を保持し、Viewクラスではカウンターの値を表示するUIを作成しています。Presenterクラスは、ViewとModelを連携し、ユーザーの入力に応じてModelを更新し、Viewを更新します。ICounterViewインターフェースは、Viewクラスによって実装され、PresenterがViewを更新するために使用されます。

このように、MVPパターンを使用することで、アプリケーションの保守性や拡張性を向上することができます。また、Presenterを使用することで、ビジネスロジックとUIを分離し、テストを容易にすることもできます。

実行結果

フォームデザイン

ラベルを1つとボタンを2つ配置します

ボタンのクリックのイベントを登録します

ソリューション

コード

Model

namespace MVPSample
{
    public class CounterModel
    {
        private int count = 0;

        public int Count
        {
            get { return count; }
            set { count = value; }
        }

        public void Increment()
        {
            count++;
        }

        public void Decrement()
        {
            count--;
        }
    }
}

View

namespace MVPSample
{
    public partial class CounterForm : Form, ICounterView
    {
        private CounterPresenter presenter;

        public CounterForm()
        {
            InitializeComponent();
            presenter = new CounterPresenter(this, new CounterModel());
        }

        public void UpdateCount(int count)
        {
            countLabel.Text = count.ToString();
        }

        private void incrementButton_Click(object sender, EventArgs e)
        {
            presenter.Increment();
        }

        private void decrementButton_Click(object sender, EventArgs e)
        {
            presenter.Decrement();
        }
    }
}
namespace MVPSample
{
    partial class CounterForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.countLabel = new System.Windows.Forms.Label();
            this.incrementButton = new System.Windows.Forms.Button();
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // countLabel
            // 
            this.countLabel.AutoSize = true;
            this.countLabel.Location = new System.Drawing.Point(97, 75);
            this.countLabel.Name = "countLabel";
            this.countLabel.Size = new System.Drawing.Size(38, 15);
            this.countLabel.TabIndex = 0;
            this.countLabel.Text = "label1";
            // 
            // incrementButton
            // 
            this.incrementButton.Location = new System.Drawing.Point(208, 58);
            this.incrementButton.Name = "incrementButton";
            this.incrementButton.Size = new System.Drawing.Size(85, 32);
            this.incrementButton.TabIndex = 1;
            this.incrementButton.Text = "インクリメント";
            this.incrementButton.UseVisualStyleBackColor = true;
            this.incrementButton.Click += new System.EventHandler(this.incrementButton_Click);
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(208, 113);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(85, 32);
            this.button1.TabIndex = 2;
            this.button1.Text = "デクリメント";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.decrementButton_Click);
            // 
            // CounterForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(384, 217);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.incrementButton);
            this.Controls.Add(this.countLabel);
            this.Name = "CounterForm";
            this.Text = "View";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private Label countLabel;
        private Button incrementButton;
        private Button button1;
    }
}

Presenter

namespace MVPSample
{
    public class CounterPresenter
    {
        private ICounterView view;
        private CounterModel model;

        public CounterPresenter(ICounterView view, CounterModel model)
        {
            this.view = view;
            this.model = model;
            view.UpdateCount(model.Count);
        }

        public void Increment()
        {
            model.Increment();
            view.UpdateCount(model.Count);
        }

        public void Decrement()
        {
            model.Decrement();
            view.UpdateCount(model.Count);
        }
    }
}

Program.cs

namespace MVPSample
{
    internal static class Program
    {
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // To customize application configuration such as set high DPI settings or default font,
            // see https://aka.ms/applicationconfiguration.
            ApplicationConfiguration.Initialize();
            Application.Run(new CounterForm());
        }
    }
}