Подтвердить что ты не робот

Да или нет: должны ли модели MVC содержать логику приложения?

Вчера у меня была дискуссия с одним из наших разработчиков относительно 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;
    }

}

Пример 2

Мой коллега полагает, что это нарушает идею MVC, он предполагает, что модель должна позаботиться об этом:

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;
    }
}

И вне модели вы бы сделали: blog.getArticles(); или article.getTags();, чтобы получить теги, не беспокоясь о вызове ajax.

Однако, насколько это возможно, я считаю, что этот подход ломается с MVC, потому что в конце дня все модели будут полны методов, которые выполняют различные фанки, а классы контроллера и помощника почти ничего не делают.

В моем понимании MVC модели должны содержать только свойства и минимум "вспомогательных методов" внутри. Например, модель "Статья" может предложить метод getNumOfTags(), но он не должен делать никаких вызовов Ajax сам по себе.

Итак, какой подход правильный?

4b9b3361

Ответ 1

В общем, я стараюсь держать контроллеры простыми с точки зрения логики. Если требуется бизнес-логика, она перейдет к классам уровня обслуживания, чтобы справиться с этим. Это также сохраняет повторение любого кода/логики, что в конечном итоге делает весь проект более удобным, если бизнес-логика должна измениться. Я просто держу модели как объекты сущности.

Я думаю, что ответ выше подводит итог, но легко спроектировать проект, основанный на шаблонах дизайна. Идите с тем, что работает для вас, и наиболее удобно или эффективно.

Ответ 2

Вы должны прекратить рассматривать "модель" в MVC как некоторый класс. Модель не является классом или объектом. Модель - это слой (в современном MVC с момента создания концепции произошли некоторые изменения). То, что люди обычно называют "моделями", на самом деле объект домена (я виню Rails за эту массовую глупость).

Логика приложения (взаимодействие между логическими структурами домена и абстракцией хранилища) должна быть частью слоя модели. Точнее: он должен находиться внутри Services.

Взаимодействие между уровнем представления (модели, представления, макеты, шаблоны) и уровнем модели должно происходить только через эти службы.

Приложение не имеет места в контроллерах. Контроллеры представляют собой структуры уровня представления, и они несут ответственность за обработку ввода пользователем. Пожалуйста, не подвергайте его объектам deomain.

Ответ 3

Правильно? Или. Они оба компилируются, не так ли?

Удобные трюки хороши, почему бы не использовать их, если бы вы могли? При этом, как вы уже указали, вы можете получить раздутые модели, если поместить в них всевозможную логику. Точно так же вы можете получить раздутые контроллеры, когда они делают огромные суммы в каждом действии. Есть способы отделить элементы от них, если это необходимо.

В конце дня все шаблоны проектирования - это рекомендации. Вы не должны слепо следовать за любым правилом, просто потому, что кто-то это сказал. Делайте то, что работает для вас, что вы думаете, дает чистый, расширяемый код и показывает, какие показатели вы считаете хорошим кодом.

Все, что сказано, для истинного идеалистического MVC я бы сказал, что модели не должны иметь никаких внешних действий, они представляют собой представления данных, не более того. Но не стесняйтесь не соглашаться: -)

Ответ 4

Ваше предложение о модулях (без какой-либо бизнес-логики внутри) больше похоже на то, что вы говорите об объектах Value. Предложение вашего колледжа больше похоже на объекты домена.

По-моему, концепция, которая будет использоваться, зависит от используемой структуры (что практический взгляд, более философский). Если используется фреймворк, он обычно устанавливает правила о том, как реализовать каждый компонент. Например, мы можем посмотреть на различные структуры MVC. В Flex Cairngorm мы имеем обе. VO (объекты Value) первично используются для привязки к представлению, тогда как DO (объекты домена) содержат бизнес-логику. Если мы посмотрим на реализацию ASP.NET MVC, у нас есть модель, которая содержит по крайней мере данные (VO), а также некоторую проверку (если требуется). Давайте посмотрим на UI MV * framework - например Backbone.js. Документация на базовую станцию ​​гласит:

Модели являются основой любого приложения JavaScript, содержащего интерактивные данные, а также большую часть логики, окружающих его: преобразования, проверки, вычисленные свойства и контроль доступа.

Если мы рассмотрим традиционный MVC, предоставленный Smalltalk, мы увидим, что: "Модель: управляет поведением и данными домена приложения", поэтому мы имеем некоторое поведение в это не просто данные.

Пусть думают практически, если в модели нет логики, вероятно, мы должны поместить всю прикладную и бизнес-логику в контроллер.

Теперь давайте сосредоточимся на конкретном примере. Представьте, что у нас есть модель, которая является графиком. Мы хотим найти кратчайший путь между двумя узлами в нем. Хороший вопрос - где поставить алгоритм, который найдет кратчайший путь? Это своего рода бизнес-логика, верно? Если мы посмотрим на основные преимущества MVC (повторное использование кода, DRY и т.д.), Мы увидим, что если мы хотим наилучшим образом использовать нашу модель, мы должны реализовать самый короткий путь внутри нее. Алгоритм кратчайшего пути обычно зависит от внутреннего представления графика (или, по крайней мере, для наилучшей производительности алгоритма), но это представление инкапсулируется в модель, к сожалению, мы не можем повторно использовать полный кратчайший путь для представления матриц и список соседей, чтобы он не хорошая идея поместить его в контроллер.

Итак, как вывод, я могу сказать, что это зависит от ваших потребностей (в основном). Традиционная цель MVC должна использоваться в пользовательском интерфейсе (внутри GoF

Триада классов Model/View/Controller (MVC) [впервые описанная Краснером и Папой в 1988 году] используется для создания пользовательских интерфейсов в Smalltalk-80.

)

теперь мы используем его в разных областях - только пользовательский интерфейс, для веб-приложений и т.д. Из-за этого он не может быть использован в чистом виде. Но в любом случае, на мой взгляд, лучшее разделение проблем может быть достигнуто путем изоляции бизнес-логики до модели и логики приложения в контроллере.

Ответ 5

Короче говоря, я считаю, что модель должна быть просто данными, которые будут отправлены на ваш просмотр. Это помогает управлять парадигмой MVC в других аспектах вашего приложения.

Если вы пытаетесь не разорвать шаблон MVC, все ваши данные должны быть возвращены как бизнес-модель для вашего контроллера и распакованы в ваш ViewModel. Запросите информацию на стороне сервера, а затем отправьте все. Если вам нужно сделать JSon-запросы, это должно быть либо службой Rest Rest, либо вызовом Controller. Наличие этих getTags и getArticles делает его очень запутанным... если ваше представление теперь решает, на какой вызов... Я не могу понять, почему у вас нет такой информации, которая не доступна заранее. Использование статических методов - это один и тот же подход под другим углом.

Я нашел, что лучше всего, чтобы мои действия с контроллером вызывали инъецированную службу, которая делает магию, и использовать Модели в веб-приложении MVC для возврата информации. Это делает вещи более аккуратными и еще более подчеркивает разделение беспокойства. После этого ваши действия контроллера становятся очень тонкими и ясно, что они делают.

Я считаю, что, начиная с рассмотрения Модели как полностью немой, может пройти долгий путь в сортировке некоторых из этих архитектурных проблем, которые я вижу из этого кода.