【问题标题】:Instantiating views, models, and databases in MVC在 MVC 中实例化视图、模型和数据库
【发布时间】:2015-02-18 04:52:53
【问题描述】:

我目前是 Python 新手,正在学习 MVC 架构模式。为简单起见和易于解释,假设我有 3 个类。 (模型、视图和控制器)。

class Controller  
  def __init__(self):
    self.view = View()
    self.model = Model()

  def some_function(self):
    return self.model.add_things(1,2)

class Model
  def __init__(self):
    pass

  def add_things(self, x, y):
    return x + y

class View:
  def __init__(self):
    pass

将我的视图和模型实例化为上述控制器的实例变量是否正常?

或者在Controller文件的顶部手动导入文件(即导入模型)并直接在控制器中调用方法更好?

from Model import Model 
from View import View

class Controller  
  def __init__(self):
     pass

 def some_function(self):
     return Model.add_things(1, 2)

class Model
  def __init__(self):
    pass

  def add_things(self, x, y):
    return x + y

class View:
  def __init__(self):
    pass

【问题讨论】:

  • 此外,我不清楚两者之间的差异(如果有的话),以及何时一种设计会比另一种更受青睐?

标签: python python-3.x model-view-controller web


【解决方案1】:

我认为你的例子不太符合标准。在您的第二个代码 sn-p 中,您仍然(可能)正在处理类(ModelView),所以这段代码对我来说似乎有点奇怪

from Model import Model 
from View import View

class Controller  

    def some_function(self):
        # How are you calling the method on the class and not the instance?
        return Model.add_things(1, 2)

您必须执行return Model().add_things(1, 2) 之类的操作才能获取一个实例,从中调用add_things 方法(除非该函数使用classmethod 进行修饰)。但是,这没有任何意义,我敢说你可能不是那个意思。您实际上似乎要求的是在构造函数中初始化对象与使用全局声明的实例之间的区别,所以 类似这样的

# It seems that for your question, it shouldn't really matter whether the 
# class `Model` is imported or declared inside the same module. So it could 
# be either way.
# 1) class Model(): pass
# 2) from Model import Model    

# This would initialize `Model` at the module-level
modelobject = Model()

class Controller  

    def some_function(self):
        # And then it would be possible to use it as you described.
        return modelobject.add_things(1, 2)

回到问题...

要回答你,我首先必须让你意识到你真正问的是什么重点是从外部导入您的 ModelView 与在使用它们的同一模块中定义它们没有任何问题或远程争议,所以 询问关于这个并没有多大意义;事实是,这实际上取决于您的程序结构,更一般地说,取决于您的项目有多大。越大越复杂,这些类或类集合就越不可能混合在同一个模块中。它们很快就会被分成不同的模块。

因此,据我所知,您真正的问题是最好在 Controller 的构造函数中初始化 ModelView 对象,或者将它们用作可以调用的全局实例来自您的Controller 班级。坦率地说,我认为您真正要问的是类似于全局实例模式的东西(例如,类似 Singleton 类的东西)。

你还没有专门使用过Singleton这个词,但是要求一种使用全局声明的类实例的方法很像这样你在问什么。

您可以阅读有关它的陷阱hereherehere

更好的方法是Dependency Injection

要引用您的原始示例,对于代码层次结构中较低的对象,最好使用以下方法(在整个程序中获得一个单个实例):

class SubController
    def __init__(self, modelobject, viewobject):
        self.view = viewobject
        self.model = modelobject

换句话说,它与 singleton 没有什么不同,因为如果这确实是您所需要的 。然而,它的工作原理不是声明一个全局实例(这会引入链接文章中讨论的耦合和许多其他问题),而是让类通过调用上下文获取其依赖项(这具有相当大的优势)。因此,您可以通过构造方法直接传递 ModelView 对象,而不是直接在类中实例化它们(如您的示例中)或使用全局声明的变量获取它们。

当然,您总是有 ma​​in 类或函数,您可以在其中实例化这些对象并从那里开始传递它们。这种方法的好处是以后会更加灵活!

【讨论】:

  • 非常感谢!在数据库连接的情况下呢?假设我没有使用 ORM,而是将 sqlite3 命令包装到一个类中。依赖注入在这里合适吗?如果是这样,我应该在Controller的构造函数中初始化吗?
  • 依赖注入是一种提倡松耦合的设计模式,所以与你选择初始化对象的哪里无关;这个想法是您将它们初始化一次(最好在程序的最高级别),以便您可以将它们传递给可能需要它们的其他对象。在包装类的情况下,如果它旨在包装一组特定的命令或类,那么在 Controller 的构造函数中初始化包装的对象确实更有意义。
  • 如果您只是从另一个模块包装模块级函数,您只需导入模块(就像您通常那样,显然不在类内部)并正常调用这些函数。关键是您必须确定一个对象是否对它正在使用和传递的对象了解太多 是否重要。例如,如果您决定将来要交换 View,则可以使用依赖注入轻松实现此目的(假设另一个 View 符合相同或相似的接口)。
猜你喜欢
  • 2012-06-11
  • 2012-01-29
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
  • 2011-10-21
相关资源
最近更新 更多