Hallo, das ist @ hairgai. Dieses Mal werde ich meine eigene Verwendung der Vor- und Nachteile der Service-Klasse schreiben.
Eine Gruppe von Klassen, die eine Funktion beschreiben, die von einem Dienst in DDD (Domain Driven Design) abgeleitet (und selbst erkannt) wird. Ich werde es weglassen, weil es viele Leute gibt, die es ausführlich erklären, aber ich benutze es oft, weil ich Geschäftslogik sauber zwischen dem Modell und dem Controller schreiben kann. Dieses Mal (obwohl meine Verwendung möglicherweise falsch ist) werde ich meine eigene Verwendung und den Teil schreiben, der ihr Verdienst zu sein scheint.
Zunächst möchte ich die grundlegende Verwendung anhand eines Codebeispiels vorstellen. (Ich bin nicht sicher, ob dies die richtige Antwort ist, aber ich denke, es ist gut, weil es leicht zu sehen ist.) Wenn Sie beispielsweise die Funktion "Folgen" auf SNS usw. als Serviceschicht in einer Datei beschreiben, sieht dies folgendermaßen aus. ** * Ich wiederhole, aber das ist nicht die richtige Antwort. ** ** **
class FollowService
attr_reader :user, :target_user
attr_accessor :follow
def initialize(user, target_user)
@user = user
@target_user = target_user
end
def perform
check!
create_follow!
run_after_worker!
end
private
def check!
check_following!
check_blocking!
end
def check_following!
return true unless user.following?(target_user)
raise ArgumentError, 'User following target user'
end
def check_blocking!
return true unless user.blocking?(target_user)
raise ArgumentError, 'User blocking target user'
end
def create_follow!
self.follow = user.follows.create!(target_user: target_user)
end
def run_after_worker!
AfterFollowWorker.perform_in(0.2.seconds, follow.id)
end
end
Grundsätzlich mache ich nichts mit Gem etc. Wir streben den Effekt an, "die Barriere für das Verständnis der Implementierung zu senken", indem wir sie in reinem Ruby implementieren. Die Serviceklasse hat in der Regel eine komplizierte Logik (wenn es um umfangreiche Funktionen geht), daher versuche ich, sie so einfach wie möglich zu halten, damit jeder sie sofort verstehen kann.
Ich denke, Sie mögen die Benennung, aber da es sich um eine Klasse handelt, die die Funktion symbolisiert, wird sie mit "verb Service" vereinheitlicht. Eine Namenskonvention hat den Vorteil, dass das Ableiten von Funktionen erleichtert wird.
Ich denke, es gibt hier eine Menge Präferenzen (viele Leute nennen es "call"), aber im Grunde wird nur eine öffentliche Methode erstellt, und die anderen können nicht aufgerufen werden. Dies liegt daran, dass die Service-Klasse eine Klasse ist, die eine einzelne Funktion symbolisiert, und die Funktionen, die mit ihr realisiert werden können, auf eine einzelne beschränkt sind. Es gibt ziemlich viele Leute, die diese einzige öffentliche Methode sagen, aber ich habe sie auch übernommen, weil es zum Zeitpunkt des Entwurfs kein Zögern gab und die Implementierungsgeschwindigkeit dramatisch anstieg.
Dies wird auch übernommen, weil es die Sichtbarkeit verbessert. + 1 Die Verantwortung für jede Methode wird leichter und die Schutzklausel wird einfacher zu verwenden. Ich denke, hier haben Sie unterschiedliche Geschmäcker.
Wie ich oben in Follow Service geschrieben habe, denke ich zuerst über die Antwort an den Benutzer nach, solange sie im Geschäftsleben verwendet wird. Als Ansatz in einem solchen Fall gibt es ein Verfahren zum "Durchführen nur der erforderlichen Verarbeitung während einer Antwort", und die nachfolgende Verarbeitung usw. wird in der Warteschlange als Job gespeichert und vom Jobserver usw. verarbeitet. Zu diesem Zeitpunkt ist die Sichtbarkeit des gesamten Projekts schlecht, wenn der Prozess des Aufrufs des Jobs auf verschiedene Stellen wie Controller und Modell verteilt ist.
Daher können Sie den Gesamtausblick verbessern, indem Sie eine Namenskonvention wie "AfterHogeJob" für Nachbearbeitungsjobs von "HogeService" verwenden und nur in der Serviceklasse aufrufen.
Unnötig zu erwähnen.
class FollowsController < ApplicationController
def create
target_user = user.find(params[:target_user_id])
service = FollowService.new(current_user, target_user)
service.perform
redirect_to user_path(target_user)
end
end
Unnötig zu erwähnen. Bringen Sie alles, was im Modell geschrieben ist, in die Service-Klasse, und das Modell besteht nur aus Datenassoziation, Validierung und anderen Methoden, die sich auf ein einzelnes Modell beziehen. Infolgedessen enthält das Modell keine logikreichen Methoden mehr und keine aufgeblähten, schwer zu erkennenden Modelle.
Wenn ich es auf diese Weise noch einmal schreibe, denke ich, dass ich auf eine Weise schreibe, die der Service-Klasse verschiedene Verantwortlichkeiten auferlegt. Ich denke, es ist fraglich, ob die Service-Klasse nicht notwendig ist, aber da eine solche Geschichte des Designs nur eine der Methoden ist, wäre es schön, wenn sie entsprechend unserem Geschäft angemessen verwendet werden könnte.
Recommended Posts