設計模式九:模型-視圖-控制器模式
什麼是模型-視圖-控制器模式
模式的名稱來自用來切分軟件應用的三個主要部分:模型部分,視圖部分和控制器部分,這是一種架構模式。
模型:代表着應用的信息本源,包含和管理邏輯,數據,狀態以及應用規則。
視圖:是模型的可視化表現。
控制器:模型與視圖之間的鏈接、粘附。
模型與視圖之間的所有通信都是通過控制器進行的。
使用優勢
1.無需修改模型就能使用多個視圖的能力
2.爲了實現模型與其表現之間的解耦,每個視圖通常都需要屬於它的控制器
3.視圖與模型的分離允許美工和程序員不會互相干擾
4.視圖與模型之間是鬆耦合,每個部分可以單獨修改/擴展,不會相互影響
5.職責分明,維護簡單
典型案例
用戶通過點擊某個按鈕出發一個視圖,視圖把用戶操作告知控制器,控制器處理用戶輸入,並與模型交互,模型執行所有必要的檢驗和狀態改變,並通知控制器應該做什麼,控制器按照模型給出的指令,知道視圖適當的更新和顯示輸出。
使用注意
從頭實現此模式,確保創建的模型很智能,控制器很瘦,視圖很傻瓜
智能模型:
包含所有的校驗、業務規則、邏輯
處理應用的狀態
訪問應用數據
不依賴UI
瘦控制器:
在用戶與視圖交互時,更新模型
模型改變時,更新視圖
如果需要,在數據傳遞給模型、視圖、之前進行處理
不展示數據
不直接訪問應用數據
不包含校驗、業務規則、邏輯
傻瓜視圖:
展示數據
允許用戶與其交互
僅做最小的數據處理,通常由一種模板語言提供處理能力
不存儲任何數據
不直接訪問應用數據
不包含校驗、業務規則、邏輯
補充知識
軟件工程相關的設計原則之一:關注點分離。將一個應用切分成不同的部分,每個部分解決一個單獨的關注點,能簡化軟件應用的開發和維護
實例代碼
import wx
import wx.xrc
import cv2
import numpy
from PIL import Image
import time
import random
import threading
class Model:
def __init__(self):
pass
def getvalue(self):
data = []
for i in range(200):
data_1 = []
for j in range(500):
x = random.randint(0,256)
data_1.append(x)
data.append(data_1)
a = numpy.array(numpy.uint8(data))
im = Image.fromarray(a)
im1 = im.convert('RGB')
idata = numpy.array(im1)
image_data = wx.BitmapFromBuffer(500,200,idata)
return image_data
class View ( wx.Frame ):
clickdown = False
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
bSizer2 = wx.BoxSizer( wx.VERTICAL )
self.m_button1 = wx.Button( self, wx.ID_ANY, u"Click", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer2.Add( self.m_button1, 0, wx.ALL|wx.EXPAND, 5 )
self.m_bitmap1 = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer2.Add( self.m_bitmap1, 1, wx.ALL|wx.EXPAND, 5 )
bSizer1.Add( bSizer2, 1, wx.EXPAND, 5 )
self.SetSizer( bSizer1 )
self.Layout()
self.Centre( wx.BOTH )
# Connect Events
self.m_button1.Bind( wx.EVT_BUTTON, self.Click )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def Click( self, event ):
self.clickdown = True
event.Skip()
def show(self,image):
self.m_bitmap1.SetBitmap(image)
class Controller:
def __init__(self):
self.view = View(None)
self.model = Model()
self.view.Show()
def run(self):
def threadrun():
while True:
event = self.view.clickdown
if event:
image = self.model.getvalue()
self.view.show(image)
self.view.clickdown = False
t = threading.Thread(target=threadrun,args=())
t.start()
if __name__ == "__main__":
app = wx.App()
controller = Controller()
controller.run()
app.MainLoop()