使用 MVC + Observer 模式组织不同的控制器

Organize different controller by using MVC + Observer pattern

假设,我们有一个 MainView 和另外两个视图。如果其他两个视图更新了她的数据,他们应该能够通知 MainView 绘制数据。我不知道如何连接和通知(使用 Event.PLOT_DATASubControllerMainController

这是一个例子:

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)

解决方案是使用 ControllerService 连接两个控制器。 ControllerService 存储 origintarget 控制器,并具有类似 redirect 的功能。此函数可以将事件发送到 target 控制器。这是一个例子:

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)