使用MVC + Observer模式组织不同的控制器
问题描述:
假设我们有一个MainView
和另外两个视图。如果其他两个视图更新她的数据,他们应该能够通知MainView
绘制数据。我不知道如何连接并通知(与Event.PLOT_DATA
)SubController
与MainController
。使用MVC + Observer模式组织不同的控制器
下面是一个例子:
class Event(object):
PLOT_DATA = 1
UPDATE_VIEW = 2
class MainModel(object):
def __init__(self):
self.x_data = []
self.y_data = []
class Model2(object):
def __init__(self):
self.x_data = []
self.y_data = []
def __repr__(self):
return "<x_data=%s, y_data=%s>" % (self.x_data, self.y_data)
def __str__(self):
return "%s %s" % (self.x_data, self.y_data)
class Controller(object):
def __init__(self):
self.model = None
self.views = []
def get_data(self):
return self.model
def register(self, view):
self.views.append(view)
def unregister(self, view):
if view in self.views:
self.views.remove(view)
def notify(self, event):
for view in self.views:
view.update(event)
class MainController(Controller):
def __init__(self):
Controller.__init__(self)
self.model = MainModel()
def change_model(self, x_data, y_data):
self.model.x_data = x_data
self.model.y_data = y_data
self.notify(Event.PLOT_DATA)
class SubController(Controller):
def __init__(self):
Controller.__init__(self)
self.model = Model2()
def change_model(self, x_data, y_data):
self.model.x_data = x_data
self.model.y_data = y_data
self.notify(Event.UPDATE_VIEW)
class MainView(object):
def __init__(self, controller):
self.controller = controller
self.controller.register(self)
self.sub_controller = SubController()
self.view1 = View1(self.sub_controller)
self.view2 = View2(self.sub_controller)
# some operations on view1 and view2
self.view1.funny_stuff()
self.view2.funny_stuff()
def plot_data(self, data):
print "Data of MainView: %s" % data
def update(self, event):
if event == Event.PlOT_DATA:
self.data = self.controller.model
self.plot_data(self.data)
class View1(object):
def __init__(self, controller):
self.controller = controller
self.controller.register(self)
self.print_data()
def print_data(self):
print "View 1 data=%s" % self.controller.get_data()
def funny_stuff(self):
print "Change data on View 1"
self.controller.change_model([0, 1, 2], [0, 1, 2])
def update(self, event):
if event == Event.UPDATE_VIEW:
print "Update View 1"
self.data = self.controller.model
self.print_data()
class View2(object):
def __init__(self, controller):
self.controller = controller
self.controller.register(self)
self.print_data()
def print_data(self):
print "View 2 data=%s" % self.controller.get_data()
def funny_stuff(self):
print "Change data on View 2"
self.controller.change_model([3, 2, 1], [3, 2, 1])
def update(self, event):
if event == Event.UPDATE_VIEW:
print "Update View 2"
self.data = self.controller.model
self.print_data()
main_controller = MainController()
main_view = MainView(main_controller)
答
的soulution是使用ControllerService
其中连接两个控制器。 ControllerService
存储origin
和target
控制器,并具有类似redirect
的功能。该功能可以将事件发送到控制器。这里是一个例子:
class Controller():
def __init__(self):
self.model = None
self.views = []
def get_data(self):
return self.model
def register(self, view):
self.views.append(view)
def unregister(self, view):
if view in self.views:
self.views.remove(view)
def notify(self, event):
for view in self.views:
view.update(event)
class Event(object):
UPDATE_VIEW = 1
PLOT_DATA = 2
FINISH_UPDATE = 3
class MainModel(object):
def __init__(self):
self.x_data = []
self.y_data = []
def __repr__(self):
return "<x_data=%s, y_data=%s>" % (self.x_data, self.y_data)
def __str__(self):
return "%s %s" % (self.x_data, self.y_data)
class Model2(object):
def __init__(self):
self.x_data = []
self.y_data = []
def __repr__(self):
return "<x_data=%s, y_data=%s>" % (self.x_data, self.y_data)
def __str__(self):
return "%s %s" % (self.x_data, self.y_data)
class ControllerService(object):
def __init__(self):
self.origin = None
self.target = None
def add_origin(self, origin):
self.origin = origin
def add_target(self, target):
self.target = target
def redirect(self, event):
if self.target:
self.target.notify(event)
else:
print "No target controller found."
class MainController(Controller):
def __init__(self, controller_service):
Controller.__init__(self)
self.model = MainModel()
self.controller_service = controller_service
self.controller_service.add_target(self)
def get_controller_service(self):
return self.controller_service
def change_model(self, x_data, y_data):
self.model.x_data = x_data
self.model.y_data = y_data
self.notify(Event.PLOT_DATA)
class SubController(Controller):
def __init__(self, controller_service):
Controller.__init__(self)
self.model = Model2()
self.controller_service = controller_service
self.controller_service.add_origin(self)
def change_model(self, x_data, y_data):
self.model.x_data = x_data
self.model.y_data = y_data
self.notify(Event.UPDATE_VIEW)
def finish_updating(self):
self.controller_service.redirect(Event.UPDATE_VIEW)
class MainView(object):
def __init__(self, controller):
self.controller = controller
self.controller.register(self)
self.controller_service = self.controller.get_controller_service()
self.sub_controller = SubController(self.controller_service)
self.view1 = View1(self.sub_controller)
self.view2 = View2(self.sub_controller)
# some operations on view1 and view2
self.view1.funny_stuff()
self.view2.funny_stuff()
self.view2.finish_updating()
def update(self, event):
if event == Event.UPDATE_VIEW:
model = self.controller_service.origin.model
self.controller.change_model(model.x_data, model.y_data)
if event == Event.PLOT_DATA:
print "Plot: %s" % self.controller.model
class View1(object):
def __init__(self, controller):
self.controller = controller
self.controller.register(self)
self.print_data()
def print_data(self):
print "View 1 data=%s" % self.controller.get_data()
def funny_stuff(self):
print "Change data on View 1"
self.controller.change_model([0, 1, 2], [0, 1, 2])
def update(self, event):
if event == Event.UPDATE_VIEW:
print "Update View 1"
self.print_data()
class View2(object):
def __init__(self, controller):
self.controller = controller
self.controller.register(self)
self.print_data()
def print_data(self):
print "View 2 data=%s" % self.controller.get_data()
def funny_stuff(self):
print "Change data on View 2"
self.controller.change_model([3, 2, 1], [3, 2, 1])
def finish_updating(self):
print "All views are updated"
self.controller.finish_updating()
def update(self, event):
if event == Event.UPDATE_VIEW:
print "Update View 2"
self.print_data()
controller_service = ControllerService()
main_controller = MainController(controller_service)
main_view = MainView(main_controller)