Un utente deve eseguire un'attività alquanto complessa sul mio sito Web (inviare una valutazione). Per fare un esempio, consideriamo che si tratta di una valutazione per un film, fatta attraverso un controller. Ci sono diversi possibili "percorsi" che la logica potrebbe seguire
- L'utente desidera annullare la sua sottomissione (ad es. non è andato al film)
- Fornisce tutti i parametri richiesti OPPURE
- L'utente invia l'invio del voto
- Fornire tutti i parametri richiesti OPPURE
- L'utente aveva già inviato la sua valutazione (e gli è stata negata l'azione)
- Altri motivi (ad es. filmato, ecc.)
Sto cercando di incapsulare tutta la logica in un servizio / mediatore, così posso anche riutilizzare la logica al di fuori di un controller (ad esempio in una console operativa).
Ho deciso di fare del controller un argomento durante questa installazione di RatingService, e questo si sta trasformando in una inversione di controllo / il servizio fa tutto. Il mio servizio conosce lo stato in cui si trova attualmente e attiva vari richiami (notifica, tracciamento, ecc.) Incluso il rendering di "flash" per l'utente tramite il controller.
Questo inizia ad avere un odore strano dato che il mio servizio si sta lentamente impossessando del controller per se stesso.
Sto mostrando un codice di esempio (Ruby on Rails) solo per illustrare il mio punto
class ReviewController
def review
ReviewService.review(reviewable, current_user,
controller: self, **review_params)
end
end
class ReviewService
def review
...
end
private
def cancelled_submission?
...
controller.flash(I18n.t(:cancelled)) if controller.present?
end
def submit_rating
...
controller.flash(I18n.t(:rating_submitted)) if controller.present?
end
def already_submitted
...
controller.flash(I18n.t(:already_submitted)) if controller.present?
end
end
Mi chiedo se sarebbe una buona pratica considerare una completa inversione di controllo e dichiarare solo metodi nel mio controller che possono essere utilizzati nel servizio.
Cioè, gira
class ReviewController
def review
...
end
end
class ReviewService
def review
...
end
private
def cancelled_submission?
...
controller.flash(I18n.t(:cancelled)) if controller.present?
end
end
In
class ReviewController
def review
...
end
# Public method, meant to be called back from the service in an inversion of control fashion
def notify_cancelled
flash(I18n.t(:cancelled)
end
end
class ReviewService
def review
...
end
private
def cancelled_submission?
...
controller.notify_cancelled if controller.present?
end
end
.. o se ci sono buone pratiche là fuori