【问题标题】:MVC Datasource: controller or model?MVC 数据源:控制器还是模型?
【发布时间】:2012-02-09 23:26:33
【问题描述】:

只是一个简单的问题:在 OOP MVC 应用程序中,一个关键原则是职责分离。因此,我认为模型和从数据库、文件、xml、webservice 等中获取模型的对象应该与模型本身分开。例如,这可以通过实现数据映射器来完成。

但是,如果我有一个可以从不同来源加载的模型,我该怎么办?模型应该负责数据源,还是控制器的责任?

一个简单的例子是可以从数据库或文件加载的配置类。控制器应该指示数据源,还是模型应该知道何时从数据库或文件中加载配置信息?

【问题讨论】:

  • 你是根据从视图传下来的变量,根据运行环境等来确定数据源的吗?
  • @BryanNaegele:不一定,但这是可能的。在配置示例中,我可能会从文件中加载一些全局配置数据,但会从数据库中加载更多(用户)特定数据。其他时候,用户将通过视图和控制器影响此决定。

标签: model-view-controller oop activerecord datamapper


【解决方案1】:

已使用框架,数据源由控制器 MachII、Model-Glue(Coldfusion 框架)以及模型层(ColdSpring)通知 - 就像 Java 中的 Spring。

我认为关键是使用对你更有意义的东西,将耦合保持在最低限度并保持一致,这意味着不要将数据源或对象依赖项放在多个地方。

您还可以考虑使用服务类型对象来抽象数据源并让它为它喜欢的任何人提供服务。

该 IOC 文件可能如下所示:

<?xml version="1.0" encoding="UTF-8"?>

<beans>

  <bean id="chartShareObj" class="model.charts.ChartShared" autowire="byType" />
  <bean id="trendChartObj" class="model.charts.TrendChart" autowire="byType" />

  <bean id="adminRightsDA0" class="org.datamentor.institution.RightsDAO">
    <constructor-arg name="dsn">
      <value>${dsn_dm}</value>
    </constructor-arg>
  </bean>

  <bean id="assessmentManager" class="model.assessment.Manager">
    <constructor-arg name="dsn">
      <value>${dsn_au}</value>
    </constructor-arg>
  </bean>

</beans>

您可以通过控制器中定义的 args 查看 args 指定的不同数据源。

【讨论】:

  • 我似乎遇到的一个问题是模型并不真正了解程序的上下文。控制器几乎与用户的当前活动耦合,模型不是。当我让模型选择时,它如何知道它是否必须从文件数据库中加载数据(继续前面的示例)。
  • @Thanton,该知识将在 IOC(控制反转)层中定义,例如 Spring。这就是我所看到的处理方式。正如您所说,模型层应该与应用程序无关,以促进应用程序之间的重用。
  • 感谢您的快速解答。就像 Bryan Naegele 的回答一样,国际奥委会似乎并没有完全回答手头的问题。工厂模式、依赖注入和上下文化查找之类的东西仍然需要在某个地方实现。在模型或控制器中应用这些模式是否有最佳实践?
  • 根据您上次的编辑,以下想法是否正确:控制器选择源,模型检查源是否存在并处理它?
  • 在控制器中实现,在某种程度上会有耦合 - 这是非常抽象和常见的模式。
【解决方案2】:

根据您的情况和响应,我建议您研究依赖注入。然后,您可以让它根据您想让它确定事物的任何一组变量来确定要使用的数据源。当我有多个数据源并希望数据源由我选择的一些预定因素确定时,我会使用这种方法。

http://en.wikipedia.org/wiki/Dependency_injection

至于谁应该处理注入,我将其留给存储库工厂并简单地要求控制器中的接口。然后工厂根据依赖注入确定提供哪个存储库。

例子:

全局基础设施类中的依赖注入:

Bind<INewsArticleRepository>().ToMethod(context => NewsRepositoryFactory.Create((NewsRepositoryFactory.RepositoryType)Enum.Parse(typeof(NewsRepositoryFactory.RepositoryType), ConfigurationManager.AppSettings["NewsArticleRepositoryProvider"])));

存储库工厂

public static INewsArticleRepository Create(RepositoryType type)
    {
        switch (type)
        {
            case RepositoryType.Mock:
                return new MockNewsArticlesRepository();
            case RepositoryType.Sql:
                return new SqlNewsArticleRepository();
            default:
                throw  new NotImplementedException();
        }
    }

在控制器中调用存储库

private INewsArticleRepository newsItemRepository;

public NewsController(INewsArticleRepository newsItemRepository)
{
    this.newsItemRepository = newsItemRepository;
}

【讨论】:

  • 依赖注入看起来确实是解决方案的一部分。然而,这似乎不是全部的答案。在这个过程中究竟应该由控制器还是模型来负责的问题仍然没有答案。
  • 确实可以,谢谢!控制器具有控制角色(顾名思义)并为(例如)存储库提供细节。这又用于操作模型。
  • 正确。控制器只想要一个存储库,它不关心从哪里来。工厂只需要被告知要提供哪个存储库以及依赖注入处理它。在某些时候必须存在耦合,但您只是试图将其最小化为变量或配置设置。
【解决方案3】:

我在 Coldbox 中这样做的方式是在模型中使用 CB 的 INJECT 方法。在构造函数的 cfargument 中,我指定:

<cfargument name="dsn" type="any" inject="coldbox:datasource:dsn">

这是通过在coldbox.cfc 文件中指定dsn 并将其称为“dsn”。我保持它的通用性,这样我就可以将这些东西复制到其他项目中,并且只需要更改 Coldbox.cfc 中的 DSN 名称。

但是在这样做之后,你会得到这样的 dsn:

variables.dsn = arguments.dsn.getName();

我希望这至少有一点帮助。

罗伯

【讨论】:

    猜你喜欢
    • 2012-06-02
    • 1970-01-01
    • 2016-05-12
    • 2011-02-24
    • 2013-10-12
    • 2016-07-31
    • 1970-01-01
    • 2016-01-25
    • 1970-01-01
    相关资源
    最近更新 更多