Model view controller 是或否:MVC中的模型应该包含应用程序逻辑吗?

Model view controller 是或否:MVC中的模型应该包含应用程序逻辑吗?,model-view-controller,design-patterns,Model View Controller,Design Patterns,昨天,我与我们的一位开发人员就MVC进行了一些讨论,更确切地说,讨论了模型组件在MVC中的作用 在我看来,模型应该只包含属性,而几乎不包含任何功能,因此模型类中的方法应该尽可能少 不过,我的同事认为,模型可以而且应该有更多的功能,提供更多的功能 这是我们争论的一个例子 示例1 假设我们想创建一个博客。博客有文章和标签。每个文章可以有多个标记,每个标记可以属于多个文章。所以我们这里有一个m:n关系 在伪代码中,它可能看起来像这样: class Article{ public int id;

昨天,我与我们的一位开发人员就MVC进行了一些讨论,更确切地说,讨论了模型组件在MVC中的作用

在我看来,模型应该只包含属性,而几乎不包含任何功能,因此模型类中的方法应该尽可能少

不过,我的同事认为,模型可以而且应该有更多的功能,提供更多的功能

这是我们争论的一个例子

示例1

假设我们想创建一个博客。博客有文章和标签。每个文章可以有多个标记,每个标记可以属于多个文章。所以我们这里有一个m:n关系

在伪代码中,它可能看起来像这样:

class Article{
    public int id;
    public String title;
    public String content;
    public Tag[] tags;

    // Constructor
    public void Article(id, title, content, tags){
        this.id = id;
        this.title = title;
        this.content = content;
        this.tags = tags;
    }
}

class Tag{
    public int id;
    public String name;

    // Constructor
    public Tag(id, name){
        this.id = id;
        this.name = name;
    }
}
现在,假设我们在这里进行松耦合工作,这意味着我们可能有一个文章实例,它还没有标记,所以我们将使用Ajax调用(到后端,它有一个包含所有信息的数据库)来获取属于我们文章的标记

棘手的部分来了。我认为,通过Ajax+JSON获取后端数据应该是控制器的工作,使用专用类,该类使用解析器处理Ajax请求:

class MyController{
    private void whatever(articleID){
        Article article = (Article) ContentParser.get(articleID, ContentType.ARTICLE);
        doSomethingWith(article);
    }
}

public abstract class ContentParser{
    public static Object get(int id, ContentType type){
        String json = AjaxUtil.getContent(id, type.toString()); // Asks the backend to get the article via JSON
        Article article = json2Article(json);

        // Just in case
        Tag[] tags = article.tags;
        if (tags == null || tags.length <= 0){
            json = AjaxUtil.getContent(article.id, ContentType.TAGS); // Gets all tags for this article from backend via ajax
            tags = json2Tags(json);
            article.tags = tags;
        }

        return article;
    }

    // Does funky magic and parses the JSON string. Then creates a new instance of Article
    public static Article json2Article(String json){
        /*
         ...
        */
        return new Article(id, title, content, tags);
    }

    // Does funky magic and parses the JSON string. Then creates a new instance of Tag
    public static Tag[] json2Tags(String json){
        /*
         ...
        */
        return tags;
    }

}
类MyController{
私人无效(articleID){
Article=(Article)ContentParser.get(articleID,ContentType.Article);
带(物品)的物品;
}
}
公共抽象类ContentParser{
公共静态对象get(int-id,ContentType){
String json=AjaxUtil.getContent(id,type.toString());//请求后端通过json获取文章
Article Article=json2Article(json);
//以防万一
Tag[]tags=article.tags;

如果(tags==null | | tags.length正确?两者都正确。它们都可以编译,不是吗

方便的技巧很好,如果可以的话,为什么不使用它们呢?也就是说,正如你所指出的,如果你把各种各样的逻辑放在模型中,你可能会得到臃肿的模型。同样地,当控制器在每个动作中做大量的操作时,你也可以得到臃肿的控制器。如果有必要,也可以从中提取元素

归根结底,所有的设计模式都是is准则。你不应该因为别人说了就盲目地遵循任何规则。做适合你的事情,做你认为可以提供干净、可扩展代码的事情,并点击任何你认为是好代码的指标


尽管如此,对于真正理想化的MVC,我想说的是模型不应该有任何外部动作,它们只是数据表示,仅此而已

一般来说,我也会尽量让控制器在逻辑方面保持简单。如果需要业务逻辑,它会转到“服务层”类来处理。这也避免了重复任何代码/逻辑,如果业务逻辑发生变化,最终会使整个项目更易于维护。我只是将模型纯粹作为实体对象保留


我认为上面的答案很好地概括了这一点,基于设计模式对项目进行过度设计是很容易的:选择适合您且最具可维护性/效率的项目。

您对模块的建议(内部没有任何业务逻辑)听起来你更喜欢谈论价值对象。你大学的建议听起来更像领域对象

在我看来,将要使用的概念取决于所使用的框架(这是实践观点,下面是更哲学的观点)。如果使用框架,它通常会设置关于如何实现每个组件的规则。 例如,我们可以看看不同的MVC框架。在Flex的框架中,我们有两个。VO(值对象)主要用于绑定到视图,而DO(域对象)持有业务逻辑。如果我们看看ASP.NET的MVC实现,我们有一个模型,其中至少包含数据(VO),但也包含一些验证(如果需要)。让我们看一看UI MV*框架-例如Backbone.js。Backbone的文档说明:

模型是任何JavaScript应用程序的核心,包含 交互式数据及其周围的大部分逻辑: 转换、验证、计算属性和访问控制

如果我们研究一下由提供的传统MVC,我们会发现:“模型:管理应用程序域的行为和数据”,因此我们在其中有一些行为,而不仅仅是简单的数据

让我们实际思考一下,如果模型中没有任何逻辑,我们可能应该将所有应用程序和业务逻辑放入控制器中

现在让我们关注一个具体的例子。假设我们有一个图形模型。我们想在其中找到两个节点之间的最短路径。一个好问题是,将找到最短路径的算法放在哪里?这是一种业务逻辑,对吗?如果我们看一下MVC的主要好处(代码重用、DRY等)我们可以看到,如果我们想以最好的方式重用我们的模型,我们应该在其中实现最短路径。最短路径算法通常取决于图的内部表示(或者至少是算法的最佳性能)但是这种表示被封装到模型中,不幸的是,我们不能重用矩阵表示和邻域列表的完整最短路径,因此将其放入控制器中不是一个好主意

因此,作为结论,我可以说,这取决于您的需求(大部分)。传统的MVC用途是在UI中使用(在GoF内部)

模型/视图/控制器(MVC)三元组类[由Krasner和Pope在>1988年首次描述]用于在Smalltalk-80中构建用户界面

)

现在我们在不同的领域使用它——仅用于UI、web应用程序等。因此,它不能以纯粹的形式使用。 但无论如何,在我看来,通过将业务逻辑隔离到模型中,将应用程序逻辑隔离到Cont中,可以实现关注点的最佳分离
class Blog{
    public int id;
    public String title;
    public Article[] articles;

    // Constructor
    public Blog(id, title, articles){
        this.id = id;
        this.title = title;
        this.articles = articles;
    }

    public void getArticles(){
        if (articles == null || articles.length <= 0){
            String json = AjaxUtil.getContent(id, ContentType.ARTICLE); // Gets all articles for this blog from backend via ajax
            articles = json2Articles(json);
        }
        return articles;
    }

    private Article[] json2Articles(String json){
        /*
         ...
        */
        return articles;
    }

}

class Article{
    public int id;
    public String title;
    public String content;
    public Tag[] tags;

    // Constructor
    public Article(id, title, content, tags){
        this.title = title;
        this.content = content;
        this.tags = tags;
    }

    public Tag[] getTags(){
        if (tags == null || tags.length <= 0){
            String json = AjaxUtil.getContent(id, ContentType.TAGS); // Gets all tags for this article from backend via ajax
            tags = json2Tags;
        }
        return tags;
    }

    // Does funky magic and parses the JSON string. Then creates a new instance of Tag
    private Tag[] json2Tags(String json){
        /*
         ...
        */
        return tags;
    }
}