最近作CAD插件相關的工做,用到了一些模式,解決對應場景的問題。 好比插件的運行實例上使用Singleton、實例內部使用了MVC(Strategy and Observer )。git
針對CAD插件,插件能夠在CAD運行過程當中屢次打開關閉,數據狀態須要保持一致,數據聯動,及多種UI佈局模式。github
一、Singleton 維持一個全局惟一實例,使得插件運行變得有「狀態」 、提高插件的打開速度。web
二、MVC 對程序結構進行解耦,方便不一樣UI進行數據互通、複用使用多種UI佈局模式。設計模式
三、在這裏本文主要針對MVC進行回顧。框架
代碼連接:https://github.com/Shawn-china/MVCDemo.gitide
模式不少,場景各不一樣一般一個模式都對應一個特定場景,因此也就沒有什麼萬能模式解決全部問題。從"Gang of Four" 總結23種設計模式以後,又不斷有新的模式被總結出來。佈局
好比:建立型模式中Singleton 維護一個全局惟一實例、Factory負責建立實例;行爲型模式解決一些運行時問題;結構型模式適用模板類問題。this
使用面向對象開一個應用程序除了知足功能需求,其次還要達到OO目標。 代碼層面可讀、高內聚低耦合、複用易擴展維護等。spa
實現目標二可經過多種途徑:遵循代碼規範、使用模式、面向抽象、面向接口、使用組合等具體的方法。插件
一些常見的開發框架中也能夠看到不少模式的影子, Vue.js中雙向綁定使用觀察者模式實現,Qt中Model/View 模式簡化了UI和數據的「交互」,一些帶發佈訂閱機制的第三方軟件。
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。一個模型能夠對應多個視圖。
以下圖示:
MVC有不少具體形式,能夠view 先行也能夠controller先行。在這裏使用圖一UML所描述的實現方式。注:本質上其實爲 Observer 與 Strategy 複合模式。
圖一
一、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); }
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 包含一個Model 一個Controller ,實現IDataObserver接口 。示例包含三個view : 一、ComboBox 二、TreeView 三、DataGridView
IDataObserver 數據觀察者
public interface IDataObserver { List<string> ObserverKeys { get; set; } string SubscriptionKey { get; set; } void Update(object data); }
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; } }
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); } }
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; } }
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 } }
三、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); } }