浅析 MVC Pattern

1、前言

最近作CAD插件相关的工做,用到了一些模式,解决对应场景的问题。 好比插件的运行实例上使用Singleton、实例内部使用了MVC(Strategy and Observer )。git

针对CAD插件,插件能够在CAD运行过程当中屡次打开关闭,数据状态须要保持一致,数据联动,及多种UI布局模式。github

一、Singleton 维持一个全局惟一实例,使得插件运行变得有“状态” 、提高插件的打开速度。web

二、MVC 对程序结构进行解耦,方便不一样UI进行数据互通、复用使用多种UI布局模式。设计模式

三、在这里本文主要针对MVC进行回顾。框架

代码连接:https://github.com/Shawn-china/MVCDemo.gitide

 

2、场景与模式

模式不少,场景各不一样一般一个模式都对应一个特定场景,因此也就没有什么万能模式解决全部问题。从"Gang of Four" 总结23种设计模式以后,又不断有新的模式被总结出来。布局

好比:建立型模式中Singleton 维护一个全局惟一实例、Factory负责建立实例;行为型模式解决一些运行时问题;结构型模式适用模板类问题。this

使用面向对象开一个应用程序除了知足功能需求,其次还要达到OO目标。 代码层面可读、高内聚低耦合、复用易扩展维护等。spa

实现目标二可经过多种途径:遵循代码规范、使用模式、面向抽象、面向接口、使用组合等具体的方法。插件

一些常见的开发框架中也能够看到不少模式的影子, Vue.js中双向绑定使用观察者模式实现,Qt中Model/View 模式简化了UI和数据的“交互”,一些带发布订阅机制的第三方软件。

 

3、MVC

MVC是挪威计算机科学家:Trygve Mikkjel Heyerdahl Reenskaug,在1979年为GUI软件设计制定的模式。参考维基百科:https://en.wikipedia.org/wiki/Trygve_Reenskaug

MVC有三种类型的“对象”。

Model 应用程序数据,

View  应用程序UI,能够有多种体现形式如:winform、wpf、控制台、web页面等,

Controller定义了View对输入的处理方式。

当Model数据更改时,它将更新View。一个模型能够对应多个视图。

以下图示:

 

4、UML 类图

MVC有不少具体形式,能够view 先行也能够controller先行。在这里使用图一UML所描述的实现方式。注:本质上其实为 Observer 与 Strategy 复合模式。

 

 

                       图一

5、Code show

一、Model 实现一个数据监听 Observer,对数据数据对象进行监听,当数据变更能够通知订阅者。

    public interface IModel
    {
        ArrayList DataObservers { get; set; }

        void RegisterObserver(IDataObserver concreteObserver, string key);

        void UnregisterObserver(IDataObserver concreteObserver);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="baseObject">Base class containing an Id field and a Name field</param>
        /// <param name="key"></param>
        void GetData(BaseObject baseObject, string key);
    }
View Code IModel

 

    public class ConcreteModel : IModel
    {
        public ArrayList DataObservers { get; set; } = new ArrayList();

        public void RegisterObserver(IDataObserver concreteObserver, string key)
        {
            if (!this.DataObservers.Contains(concreteObserver))
            {
                this.DataObservers.Add(concreteObserver);
            }
        }

        public void UnregisterObserver(IDataObserver concreteObserver)
        {
            if (this.DataObservers.Contains(concreteObserver))
            {
                this.DataObservers.Remove(concreteObserver);
            }
        }

        public void GetData(BaseObject baseObject, string key)
        {
            this.Notity(baseObject, key);
        }

        private void Notity(BaseObject baseObject, string key)
        {
            foreach (object item in this.DataObservers)
            {
                if (((IDataObserver)item).ObserverKeys.Contains(key))
                {
                    ((IDataObserver)item).Update(baseObject);
                }
            }
        }
    }
View Code ConcreteModel

 

二、view 包含一个Model 一个Controller  ,实现IDataObserver接口 。示例包含三个view : 一、ComboBox 二、TreeView 三、DataGridView

IDataObserver 数据观察者

    public interface IDataObserver
    {
        List<string> ObserverKeys { get; set; }

        string SubscriptionKey { get; set; }

        void Update(object data);
    }
View Code IDataObserver

 

BaseRequest 做为全部view类的基类,包含一个Model 一个Controller

    public class BaseRequest
    {
        public static IModel ConcreteModel;
        public static IController ConcreteController;

        public BaseRequest()
        {
            ConcreteModel = ConcreteModel ?? new ConcreteModel();
            ConcreteController = ConcreteController ?? new ConcreteController(ConcreteModel);
        }

        public BaseRequest(IModel concreteModel, IController concreteController)
        {
            ConcreteModel = ConcreteModel ?? concreteModel;
            ConcreteController = ConcreteController ?? concreteController;
        }
    }
View Code BaseRequest

 

 ComboBox ,被TreeView 和 DataGridView 观察 。

    public class ConcreteComboxRequest : BaseRequest, IDataObserver
    {
        private readonly ComboBox _comboBox;

        public ConcreteComboxRequest(ComboBox comboBox)
        {
            this._comboBox = comboBox;
            this.IntializeView();
        }

        public List<string> ObserverKeys { get; set; }

        public string SubscriptionKey { get; set; } = $"{nameof(ConcreteComboxRequest)}";

        public void Update(object data)
        {
            this._comboBox.DataSource = DataContainer.Schools;
        }

        private void IntializeView()
        {
            this._comboBox.DisplayMember = "Name";
            this._comboBox.ValueMember = "Id";
            this._comboBox.SelectedIndexChanged += this.cmb_SelectedValueChanged;
        }

        private void cmb_SelectedValueChanged(object sender, EventArgs e)
        {
            BaseObject baseObject = (BaseObject)this._comboBox.SelectedItem;
            ConcreteController.GetDatas(baseObject, this.SubscriptionKey);
        }
    }
View Code ConcreteComboxRequest

 

TreeView,注册到Model监听Observer中,观察ComboBox。 同时被DataGridView 观察

public class ConcreteTreeviewRequest : BaseRequest, IDataObserver
    {
        private readonly TreeView _treeView;

        public ConcreteTreeviewRequest(TreeView treeView)
        {
            this._treeView = treeView;
            this.IntializeView();
        }

        public List<string> ObserverKeys { get; set; } = new List<string> { $"{nameof(ConcreteComboxRequest)}" };

        public string SubscriptionKey { get; set; } = $"{nameof(ConcreteTreeviewRequest)}";

        public void Update(object data)
        {
            BaseObject baseObject = (BaseObject)data;
            this.InitializeTreeView(baseObject);
        }

        private void IntializeView()
        {
            foreach (string observerKey in this.ObserverKeys)
            {
                ConcreteModel.RegisterObserver(this, observerKey);
            }

            this._treeView.AfterSelect += this.treeView_SelectedValue;
        }

        private void InitializeTreeView(BaseObject baseObject)
        {
            this._treeView.Nodes.Clear();
            List<Grade> grades = Grade.GetList(baseObject);

            foreach (Grade item in grades)
            {
                this.CreateTreeNode(null, item);
            }
        }

        private void treeView_SelectedValue(object sender, TreeViewEventArgs e)
        {
            TreeNode currentNode = this._treeView.SelectedNode;

            BaseObject baseObject = (BaseObject)currentNode.Tag;

            ConcreteController.GetDatas(baseObject, this.SubscriptionKey);
        }

        private TreeNode CreateTreeNode(TreeNode parentNode, BaseObject concreteData)
        {
            TreeNode treeNode = new TreeNode
            {
                Tag = concreteData,
                Name = concreteData.Id,
                Text = concreteData.Name
            };

            if (parentNode == null)
            {
                this._treeView.Nodes.Add(treeNode);
            }
            else
            {
                parentNode.Nodes.Add(treeNode);
            }

            return treeNode;
        }
    }
View Code ConcreteTreeviewRequest

 

DataGridView,,注册到Model监听Observer中,观察ComboBox、TreeView 。

public class ConcreteDataGridViewRequest : BaseRequest, IDataObserver
    {
        private readonly DataGridView _dataGridView;

        public ConcreteDataGridViewRequest(DataGridView dataGridView)
        {
            this._dataGridView = dataGridView;
            this.IntializeView();
        }

        public List<string> ObserverKeys { get; set; } = new List<string>
        {
            $"{nameof(ConcreteTreeviewRequest)}",
            $"{nameof(ConcreteComboxRequest)}"
        };

        public string SubscriptionKey { get; set; } = $"{nameof(ConcreteDataGridViewRequest)}";

        public void Update(object data)
        {
            BaseObject baseObject = (BaseObject)data;
            this.InitializeDataGridView(baseObject);
        }

        private void InitializeDataGridView(BaseObject baseObject)
        {
            this._dataGridView.Columns.Clear();
            List<Student> students = Student.GetList(baseObject);

            this._dataGridView.DataSource = students;
        }

        private void IntializeView()
        {
            foreach (string observerKey in this.ObserverKeys)
            {
                ConcreteModel.RegisterObserver(this, observerKey);
            }

            this._dataGridView.SelectionChanged += this.dataGridView_SelectionChanged;
        }

        private void dataGridView_SelectionChanged(object sender, EventArgs e)
        {
            // Do some business logic
        }
    }
View Code ConcreteDataGridViewRequest

 

三、Controller 包含一个 Model ,当某一view “主题”变化时,调用Model 通知对应的订阅对象。

  public interface IController { void GetDatas(BaseObject baseObject, string subscriberKey); } 

    public class ConcreteController : IController
    {
        private readonly IModel _model;

        public ConcreteController(IModel model)
        {
            this._model = model;
        }

        public void GetDatas(BaseObject baseObject, string subscriberKey)
        {
            this._model.GetData(baseObject, subscriberKey);
        }
    }
View Code ConcreteController
相关文章
相关标签/搜索