Насколько точна «логика бизнеса должна быть в сервисе, а не в модели»?

Ситуация

Ранее этим вечером я дал answer на вопрос о StackOverflow.

Вопрос:

  

Редактирование существующего объекта должно выполняться на уровне репозитория или в сервисе?

     

Например, если у меня есть Пользователь, у которого есть долг. Я хочу изменить свой долг. Должен ли я делать это в UserRepository или в сервисе, например BuyingService, получая объект, редактируя его и сохраняя его?

Мой ответ:

  

Вы должны оставить ответственность за изменение объекта на тот же объект и использовать репозиторий для извлечения этого объекта.

Пример ситуации:

class User {
    private int debt; // debt in cents
    private string name;

    // getters

    public void makePayment(int cents){
        debt -= cents;
    }
}

class UserRepository {
    public User GetUserByName(string name){
        // Get appropriate user from database
    }
}

Комментарий, который я получил:

  

Бизнес-логика должна действительно быть в сервисе. Не в модели.

Что говорит интернет?

Итак, это заставило меня искать, так как я никогда (сознательно) не использовал сервисный уровень. Я начал читать на шаблоне Service Layer и шаблоне Unit Of Work, но пока не могу сказать, что убежден, что должен использоваться сервисный уровень.

Возьмите, к примеру, эту статью от Мартина Фаулера о анти-образце модели анемичного домена

  

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

     

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

Для меня это, казалось, было именно тем, о чем шла речь: я выступал за манипулирование данными объекта, введя методы внутри этого класса, которые делают именно это. Однако я понимаю, что это должно быть задано в любом случае и, вероятно, больше связано с тем, как эти методы вызывают (используя репозиторий).

У меня также было ощущение, что в этой статье (см. ниже) уровень сервиса больше рассматривается как faà §ade , который делегирует работу основной модели, чем фактический рабочий слой.

  

Уровень приложения [его имя для уровня обслуживания]: определяет задания, которые должно выполнять программное обеспечение, и направляет объекты выразительных доменов для решения проблем. Задачи, на которые этот уровень отвечает, имеют смысл для бизнеса или необходимы для взаимодействия с уровнями приложений других систем. Этот слой остается тонким. Он не содержит бизнес-правил или знаний, а только координирует задачи и делегирует работу для совместной работы объектов домена в следующем слое. Он не имеет состояния, отражающего деловую ситуацию, но может иметь состояние, которое отражает ход выполнения задачи для пользователя или программы.

Подкрепляется здесь :

  

Сервисные интерфейсы. Сервисы предоставляют интерфейс службы, к которому отправляются все входящие сообщения. Вы можете придумать интерфейс службы как фасад, который предоставляет бизнес-логику, реализованную в приложении (как правило, логику бизнес-уровня) потенциальным потребителям.

И здесь :

  

Уровень сервиса должен быть лишен любого приложения или бизнес-логики и должен фокусироваться прежде всего на нескольких проблемах. Он должен включать вызовы Business Layer, переводить ваш домен на общий язык, который ваши клиенты могут понять, и обрабатывать среду связи между сервером и запрашивающим клиентом.

Это серьезный контраст с другими ресурсами , который поговорите об уровне обслуживания:

Уровень сервиса должен состоять из классов с методами, которые являются единицами работы с действиями, принадлежащими к одной и той же транзакции.

Или второй ответ на вопрос I ' ve уже связаны:

  

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

"Решение"?

Следуя рекомендациям в этом ответе , я придумал следующий подход, который использует уровень обслуживания:

class UserController : Controller {
    private UserService _userService;

    public UserController(UserService userService){
        _userService = userService;
    } 

    public ActionResult MakeHimPay(string username, int amount) {
        _userService.MakeHimPay(username, amount);
        return RedirectToAction("ShowUserOverview");
    }

    public ActionResult ShowUserOverview() {
        return View();
    }
}

class UserService {
    private IUserRepository _userRepository;

    public UserService(IUserRepository userRepository) {
        _userRepository = userRepository;
    }

    public void MakeHimPay(username, amount) {
        _userRepository.GetUserByName(username).makePayment(amount);
    }
}

class UserRepository {
    public User GetUserByName(string name){
        // Get appropriate user from database
    }
}

class User {
    private int debt; // debt in cents
    private string name;

    // getters

    public void makePayment(int cents){
        debt -= cents;
    }
}

Заключение

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

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

  • Является ли это средством просто извлечь логику из контроллера и поместить ее внутри службы?

  • Предполагается ли он заключить контракт между контроллером и доменом?

  • Должен ли быть слой между доменом и уровнем обслуживания?

И последнее, но не менее важное: после оригинального комментария

  

Бизнес-логика должна действительно быть в сервисе. Не в модели.

  • Правильно ли это?

    • Как мне представить свою бизнес-логику в службе вместо модели?
350 голосов | спросил Jeroen Vannevel 10 72013vEurope/Moscow11bEurope/MoscowSun, 10 Nov 2013 01:54:23 +0400 2013, 01:54:23

12 ответов


322

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

Сервис не является каноническим или универсальным программным термином. Фактически, суффикс Service для имени класса очень похож на сильно замаскированный Manager : он почти ничего не говорит о том, что объект на самом деле делает .

В действительности, то, что должна делать служба, имеет особую архитектуру:

  1. В традиционной многоуровневой архитектуре service буквально является синонимом уровня бизнес-логики . Это слой между пользовательским интерфейсом и данными. Таким образом, бизнес-правила все входят в сервисы. Уровень данных должен понимать только основные операции CRUD, а слой пользовательского интерфейса должен иметь дело только с отображением DTO представления в бизнес-объекты и из них.

  2. В распределенной архитектуре в стиле RPC (SOAP, UDDI, BPEL и т. д.) служба является логической версией физической конечной точки . Это, по сути, набор операций, которые разработчик хочет предоставить в качестве публичного API. Различные руководства по лучшим практикам объясняют, что сервис должен фактически быть операцией бизнес-уровня, а не CRUD, и я склонен согласиться.

    Однако, поскольку маршрутизация все через фактический удаленный сервис может серьезно повредить производительность, обычно лучше not использовать эти службы для реализации самой бизнес-логики; вместо этого они должны обернуть «внутренний» набор бизнес-объектов. Одна служба может включать один или несколько бизнес-объектов.

  3. В архитектуре MVP /MVC /MVVM /MV * services вообще не существует. Или, если это так, этот термин используется для обозначения любого общего объекта, который может быть введен в контроллер или модель представления. Бизнес-логика находится в вашей модели . Если вы хотите создать «объекты обслуживания» для организации сложных операций, это рассматривается как деталь реализации. К сожалению, многие люди реализуют MVC, но это считается анти-шаблоном ( модель анемичного домена ), поскольку сама модель ничего не делает, это всего лишь куча свойств для пользовательского интерфейса.

    Некоторые люди ошибочно полагают, что использование метода 100-строчного контроллера и превращение его в услугу каким-то образом создает лучшую архитектуру. Это действительно не так; все, что он делает, это добавить другой, возможно, ненужный слой косвенности. Практически говоря, контроллер все еще выполняет свою работу, он просто делает это через плохо названный «вспомогательный» объект. Я настоятельно рекомендую презентацию Wicked Domain Models Джимми Богарда, чтобы ясный пример того, как превратить модель анемичного домена в полезную. Это требует тщательного изучения моделей, которые вы публикуете, и какие операции действительно действительны в контексте business .

    Например, если ваша база данных содержит Orders, и у вас есть столбец Total Amount, ваше приложение , вероятно, , не должно быть разрешено фактически изменить это поле на произвольное значение, потому что (a) это история и (б) она должна определяться тем, что в порядке, а также, возможно, некоторыми другими чувствительными к времени данными /правилами. Создание службы для управления заказами не обязательно решает эту проблему, потому что код пользователя может еще захватывать фактический объект Order и изменять его количество. Вместо этого сам заказ должен отвечать за то, что он может быть изменен только безопасными и последовательными способами.

  4. В DDD услуги предназначены специально для ситуации когда вы выполните операцию, которая не будет должным образом принадлежать ни одному агрегированному корню . Вы должны быть осторожны здесь, потому что часто потребность в услуге может означать, что вы не использовали правильные корни. Но предполагая, что вы это сделали, служба используется для координации операций по нескольким корням или иногда для устранения проблем, которые вообще не связаны с моделью домена (например, возможно, для записи информации в базу данных BI /OLAP).

    Одним из примечательных аспектов службы DDD является то, что разрешено использовать сценарии транзакций . При работе с большими приложениями вы, скорее всего, в конечном итоге столкнетесь с примерами, когда проще всего выполнить что-то с помощью процедуры T-SQL или PL /SQL, чем для суеты с моделью домена. Это нормально, и оно принадлежит службе.

    Это радикальный отход от определения сервисов с многоуровневой архитектурой. Уровень сервиса инкапсулирует объекты домена; служба DDD инкапсулирует все не в объектах домена и не имеет смысла быть.

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

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

    Таким образом, по определению SOA каждая часть бизнес-логики где-либо содержится внутри службы, но опять же, так же как и вся система . В службах SOA могут быть компоненты , и они могут иметь конечные точки , но довольно опасно называть любой фрагмент кода service , потому что он конфликтует с тем, что должно означать исходное «S».

    Поскольку SOA, как правило, очень заинтересована в обмене сообщениями, операции, которые вы, возможно, упаковали в службу раньше, обычно инкапсулированы в обработчики , но множественность отличается. Каждый обработчик обрабатывает один тип сообщения, один . Это строгая интерпретация принципа Единого принципа ответственности , но он обеспечивает большую ремонтопригодность, поскольку каждая возможная операция выполняется в своем классе. Таким образом, вам не нужна нужна централизованная бизнес-логика, потому что команды представляют собой бизнес-операции, а не технические.

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

Нет правильного или неправильного ответа, только то, что относится к вашей ситуации.

ответил Aaronaught 14 42013vEurope/Moscow11bEurope/MoscowThu, 14 Nov 2013 07:15:55 +0400 2013, 07:15:55
35

Что касается вашего title , я не думаю, что этот вопрос имеет смысл. Модель MVC состоит из данных и бизнес-логики. Говорить, что логика должна быть в Сервисе, а не в Модели, как сказать: «Пассажир должен сидеть на сиденье, а не в машине».

И снова термин «модель» является перегруженным термином. Возможно, вы не имели в виду модель MVC, но вы имели в виду модель в смысле объекта передачи данных (DTO). AKA - сущность. Это то, о чем говорит Мартин Фаулер.

Как я это вижу, Мартин Фаулер говорит о вещах в идеальном мире. В реальном мире Hibernate и JPA (на землях Java) DTO являются супертекучей абстракцией. Я бы хотел поставить свою бизнес-логику в свою сущность. Это сделает вещи чище. Проблема заключается в том, что эти объекты могут существовать в управляемом /кэшированном состоянии, которое очень сложно понять и постоянно мешает вашим усилиям. Подводя итог моему мнению: Мартин Фаулер рекомендует правильный путь, но ОРМ не позволяют вам это делать.

Я думаю, что у Боба Мартина есть более реалистичное предложение и он дает это в этом видео, которое не является бесплатным . Он говорит о том, что ваши DTO не имеют логики. Они просто хранят данные и переносят их на другой слой, который гораздо ориентирован на объекты и не использует DTO напрямую. Это позволяет избежать протекающей абстракции от кусания вас. Слой с DTO и самими DTO не являются OO. Но как только вы выходите из этого слоя, вы становитесь как OO, как защищает Мартин Фаулер.

Преимущество этого разделения заключается в том, что он абстрагирует слой сохранения. Вы можете переключиться с JPA на JDBC (или наоборот), и ни одна из бизнес-логики не изменится. Это просто зависит от DTO, не важно, как эти DTO заселяются.

Чтобы слегка изменить темы, вам нужно учитывать тот факт, что базы данных SQL не являются объектно-ориентированными. Но у ORM обычно есть сущность - которая является объектом - за столом. Так что с самого начала вы уже проиграли битву. По моему опыту, вы никогда не сможете представить объект Entity именно так, как хотите, объектно-ориентированным способом.

Что касается службы a , Боб Мартин будет против класса с именем FooBarService. Это не объектно-ориентированное. Что делает служба? Anything , связанный с FooBars. Он также может быть помечен как FooBarUtils. Я думаю, что он защищал бы сервисный уровень (лучшим именем был бы уровень бизнес-логики), но каждый класс в этом слое имел бы содержательное имя.

ответил Daniel Kaplan 13 32013vEurope/Moscow11bEurope/MoscowWed, 13 Nov 2013 02:29:13 +0400 2013, 02:29:13
22

Я сейчас работаю над проектом «greenfield», и вчера мы должны были принять несколько архитектурных решений. Как ни странно, мне пришлось пересмотреть несколько разделов «Шаблоны архитектуры корпоративных приложений».

Вот что мы придумали:

  • Уровень данных. Запрашивает и обновляет базу данных. Слой обнажается через инъецируемые репозитории.
  • Уровень домена. Здесь живет бизнес-логика. Этот слой использует инъекционные репозитории и отвечает за большинство бизнес-логики. Это ядро ​​приложения, которое мы тщательно проверим.
  • Сервисный уровень. Этот уровень взаимодействует с доменным уровнем и обслуживает клиентские запросы. В нашем случае уровень сервиса довольно прост - он передает запросы на доменный уровень, обрабатывает безопасность и несколько других проблем, связанных с перекрестным отключением. Это не сильно отличается от контроллера в приложении MVC - контроллеры малы и просты.
  • Клиентский уровень. Переключается на сервисный уровень через SOAP.

В итоге получим следующее:

Клиент -> Сервис -> Домен -> Данные

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

Сказав все это, я думаю, что это довольно близко к тому, что подразумевал Мартин Фаулер, говоря

  

Эти службы живут поверх модели домена и используют домен   модель для данных.

Диаграмма ниже иллюстрирует это довольно хорошо:

http://martinfowler.com/eaaCatalog/serviceLayer.html

  

http://martinfowler.com/eaaCatalog/ServiceLayerSketch.gif

ответил CodeART 14 42013vEurope/Moscow11bEurope/MoscowThu, 14 Nov 2013 00:37:50 +0400 2013, 00:37:50
8

Это одна из тех вещей, которая действительно зависит от варианта использования. Общая точка уровня сервиса заключается в объединении бизнес-логики вместе. Это означает, что несколько контроллеров могут вызывать один и тот же UserService.MakeHimPay (), не заботясь о том, как делается платеж. То, что происходит в сервисе, может быть таким же простым, как изменение свойства объекта, или оно может выполнять сложную логику, связанную с другими службами (т. Е. Вызывать сторонние службы, вызывать логику проверки или даже просто сохранять что-то в базе данных. )

Это не означает, что вам нужно отключить логику ALL от объектов домена. Иногда просто имеет смысл иметь метод на объекте домена делать некоторые вычисления сами по себе. В вашем последнем примере служба является избыточным уровнем поверх объекта репозитория /домена. Он обеспечивает хороший буфер от изменений требований, но это действительно не обязательно. Если вы считаете, что вам нужна услуга, попробуйте сделать так, чтобы вместо объекта домена простую логику «изменить свойство X на объекте Y». Логика на классах доменов имеет тенденцию попадать в «вычислять это значение из полей», а не подвергать все поля через геттеры /сеттеры.

ответил firelore 10 72013vEurope/Moscow11bEurope/MoscowSun, 10 Nov 2013 04:55:53 +0400 2013, 04:55:53
7

Самый простой способ проиллюстрировать, почему программисты уклоняются от размещения логики домена в объектах домена, заключается в том, что они обычно сталкиваются с ситуацией «где я могу поставить логику проверки»? Возьмите этот объект домена, например:

public class MyEntity
{
    private int someProperty = 0;

    public int SomeProperty
    {
        get { return this.someProperty; }
        set
        {
            if(value < 0) throw new ArgumentOutOfRangeException("value");
            this.someProperty = value;
        }
    }
}

Итак, у нас есть базовая логика проверки в сеттер (не может быть отрицательной). Проблема в том, что вы не можете действительно использовать эту логику повторно. Где-то есть экран или ViewModel или Контроллер, который должен выполнить проверку до , он фактически совершает изменение объекта домена, так как он должен информировать пользователя либо до, либо когда они нажимают кнопку «Сохранить», они не могут этого сделать, и почему . Тестирование исключения, когда вы вызываете setter, является уродливым взломом, потому что вы действительно должны были выполнить все проверки до того, как вы даже начали транзакцию.

Вот почему люди перемещают логику валидации в какой-то сервис, например MyEntityValidator. Затем сущность и вызывающая логика могут получить ссылку на службу проверки и повторно использовать ее.

Если вы не выполняете , и вы все еще хотите повторно использовать логику проверки, вы вставляете ее в статические методы класса сущности:

public class MyEntity
{
    private int someProperty = 0;

    public int SomeProperty
    {
        get { return this.someProperty; }
        set
        {
            string message;
            if(!TryValidateSomeProperty(value, out message)) 
            {
                throw new ArgumentOutOfRangeException("value", message);
            }
            this.someProperty = value;
        }
    }

    public static bool TryValidateSomeProperty(int value, out string message)
    {
        if(value < 0)
        {
            message = "Some Property cannot be negative.";
            return false;
        }
        message = string.Empty;
        return true;
    }
}

Это сделает вашу модель домена менее «анемичной» и сохранит логику проверки рядом с этим свойством, что отлично, но я не думаю, что кому-то действительно нравятся статические методы.

ответил Scott Whitlock 11 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 11 Sep 2014 18:47:54 +0400 2014, 18:47:54
4

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

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

ответил Mr Cochese 10 72013vEurope/Moscow11bEurope/MoscowSun, 10 Nov 2013 03:57:38 +0400 2013, 03:57:38
4

Я думаю, что ответ ясен, если вы читаете статью статьи модели анемичного домена Мартина Фаулера .

Удаление бизнес-логики, которая является доменом, из модели домена существенно разрушает объектно-ориентированный дизайн.

Давайте рассмотрим наиболее основную объектно-ориентированную концепцию: объект инкапсулирует данные и операции. Например, закрытие учетной записи - это операция, которую объект учетной записи должен выполнять сам по себе; поэтому, имея служебный уровень, эта операция не является объектно-ориентированным решением. Это процедурный подход, и это то, о чем говорит Мартин Фаулер, когда он говорит о модели анемической области.

Если у вас есть служебный уровень, закройте учетную запись, вместо того, чтобы закрыть объект учетной записи, у вас нет объекта реальной учетной записи. Объект вашей учетной записи - это просто структура данных. То, что вы в конечном итоге, как предлагает Мартин Фаулер, - это куча сумок с геттерами и сеттерами.

ответил Carlos A Merighe - Utah 9 PMpThu, 09 Apr 2015 15:28:33 +030028Thursday 2015, 15:28:33
2

Версия tl; dr:
Мой опыт и мнения говорят, что любые объекты, имеющие бизнес-логику, должны быть частью модели домена. Модель данных, вероятно, не должна иметь никакой логики. Услуги, вероятно, должны связывать их вместе, и иметь дело с сквозными проблемами (базы данных, протоколирование и т. Д.). Тем не менее, принятый ответ является наиболее практичным.

Более длинная версия, на которую ссылаются другие, заключается в том, что слово «модель» имеет двусмысленность. Почта переключается между моделью данных и моделью домена, как если бы они были одинаковыми, что является очень распространенной ошибкой. Также может быть небольшая двусмысленность в слове «услуга».

В практическом плане у вас не должно быть сервиса, который вносит изменения в любые объекты домена; причина в том, что у вашей службы, вероятно, будет какой-то метод для каждого свойства вашего объекта, чтобы изменить значение этого свойства. Это проблема, потому что тогда, если у вас есть интерфейс для вашего объекта (или даже если нет), служба перестает следовать принципу открытого закрытия; вместо этого, всякий раз, когда вы добавляете больше данных в свою модель (независимо от домена и данных), вам приходится добавлять дополнительные функции в свою службу. Есть некоторые способы обойти это, но это самая распространенная причина, по которой я видел, что «корпоративные» приложения терпят неудачу, особенно когда эти организации считают, что «предприятие» означает «иметь интерфейс для каждого объекта в системе». Можете ли вы представить, как добавлять новые методы в интерфейс, а затем к двум или трем различным реализациям (встроенная в приложение, макетная и отладочная, встроенная память?), Только для одного свойства вашей модели? Мне кажется ужасной идеей.

Здесь больше проблемы, в которую я не буду входить, но суть такова: объектно-ориентированное программирование Hardcore говорит, что никто из релевантного объекта не должен иметь возможность изменять значение свойства внутри объекта, ни даже «видеть» значение свойства внутри объекта. Это можно облегчить, сделав данные доступными только для чтения. Вы все еще можете столкнуться с проблемами, например, когда многие люди используют данные даже в режиме «только для чтения», и вам нужно изменить тип этих данных. Вполне возможно, что все потребители должны будут измениться, чтобы это учесть. Вот почему, когда вы делаете API доступным для всех и каждого, вам рекомендуется не иметь общедоступных или даже защищенных свойств /данных; именно поэтому ООП был изобретен, в конечном счете.

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

  

В DDD сервисы предназначены специально для ситуации, когда у вас есть операция, которая не относится к корневому узлу. Вы должны быть осторожны здесь, потому что часто потребность в услуге может означать, что вы не использовали правильные корни. Но предполагая, что вы это сделали, служба используется для координации операций по нескольким корням или иногда для обработки проблем, которые вообще не связаны с моделью домена ...

ответил WolfgangSenff 15 52013vEurope/Moscow11bEurope/MoscowFri, 15 Nov 2013 23:52:16 +0400 2013, 23:52:16
1

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

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

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

ответил sunny 13 32013vEurope/Moscow11bEurope/MoscowWed, 13 Nov 2013 12:17:59 +0400 2013, 12:17:59
0

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

  

Модель состоит из данных приложения, бизнес-правил, логики и функций.    http://en.wikipedia.org/wiki/Model % E2% 80% 93view% E2% 80% 93controller

ответил stonemetal 13 32013vEurope/Moscow11bEurope/MoscowWed, 13 Nov 2013 01:37:14 +0400 2013, 01:37:14
0

Концепцию уровня обслуживания можно просмотреть с точки зрения DDD. Аароноут упомянул об этом в своем ответе, я просто немного об этом поразмышляю.

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

class WebBroserController
{
    public function purchaseOrder()
    {
        $data = $_POST;

        $responseData =
            new PurchaseOrderApplicationService(
                new PayPalClient(),
                new OrderRepository()
            )
        ;

        $response = new HtmlView($responseData);
    }
}

Если я пишу функциональный тест, я хочу использовать поддельный клиент для оплаты, и, вероятно, мне не нужен html-ответ. Таким образом, мой контроллер может выглядеть так:

class FunctionalTestController
{
    public function purchaseOrder()
    {
        $data = $_POST;

        $responseData =
            new PurchaseOrderApplicationService(
                new FakePayPalClient(),
                new OrderRepository(),
                $data
            )
        ;

        return new JsonData($responseData);
    }
}

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

Итак, отвечая на ваши вопросы с этой точки зрения:

  

Это средство просто извлечь логику из контроллера и поставить ее   внутри службы вместо?

Нет.

  

Предполагается ли он заключить контракт между контроллером и   домен?

Ну, можно так назвать.

  

Должен ли быть слой между доменом и уровнем обслуживания?

Неа.


Существует радикально иной подход, хотя это полностью отрицает использование любого вида услуг. Например, Дэвид Уэст в своей книге Object Thinking утверждает, что любой объект должен иметь все необходимое ресурсов для выполнения своей работы. Этот подход приводит, например, к отбрасыванию любого ORM .

ответил Zapadlo 3 52017vEurope/Moscow11bEurope/MoscowFri, 03 Nov 2017 16:19:20 +0300 2017, 16:19:20
-2

Для записи.

SRP:

  1. Model = Data, здесь идет сеттер и геттеры.
  2. Логика /Сервисы = здесь принимают решения.
  3. Репозиторий /DAO = здесь мы permantenty храним или извлекаем информацию.

В этом случае, выполните следующие действия:

Если долг не потребует определенного расчета:

userObject.Debt = 9999;

Однако, если для этого требуется некоторый расчет, то:

userObject.Debt= UserService.CalculateDebt(userObject)

, а также

UserService.UpdateDebt(userObject)

Но также, если вычисление выполняется на уровне сохранения, такая процедура хранения затем

UserRepository.UpdateDebt(userObject)

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

User userObject=UserRepository.GetUserByName(somename);
UserService.UpdateDebt(userObject)

И если для этого требуется сохранить его, мы можем добавить третий шаг

User userObject=UserRepository.GetUserByName(somename);
UserService.UpdateDebt(userObject)
UserRepository.Save(userobject);

О предлагаемом решении

a) Мы не должны бояться оставить конечного разработчика написать пару вместо того, чтобы инкапсулировать его в функцию.

b) И о интерфейсе, некоторые разработчики любят интерфейс, и они в порядке, но в некоторых случаях они вообще не нужны.

c) Целью службы является создание одного без атрибутов, главным образом потому, что мы можем использовать функции Shared /Static. Это также легко провести тестирование.

ответил magallanes 11 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 11 Sep 2014 16:28:58 +0400 2014, 16:28:58

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132