Diese Frage hat sehr gute Arbeit geleistet, um meine Verwirrung in dieser Angelegenheit ein wenig zu beseitigen, aber es fällt mir schwer, zuverlässige Quellen für die genauen Einschränkungen der Serviceschicht zu finden.
Nehmen wir für dieses Beispiel an, dass wir es mit Büchern zu tun haben und Bücher nach Autor abrufen möchten. Die BookDataMapper
könnte ein Generikum haben get()
Methode, die Bedingungen wie die eindeutige Kennung des Buchs, den Namen des Autors usw. akzeptiert. Diese Implementierung ist ziemlich trivial (logisch), aber was ist, wenn wir mehrere Bedingungen haben möchten, die eine komplexere Abfrage erfordern?
Nehmen wir an, wir möchten alle Bücher, die von einem bestimmten Autor unter einem bestimmten Verlag geschrieben wurden, erhalten. Wir könnten die erweitern BookDataMapper->get()
Methode, um mehrere Bedingungen zu parsen, oder wir könnten eine neue Methode schreiben, wie z BookDataMapper->getByAuthorAndPublisher()
.
Ist es vorzuziehen, dass die Serviceschicht diese aufruft? [more specific] Methoden direkt, oder lassen Sie die Bedingungen analysieren, bevor Sie die generischeren aufrufen BookDataMapper->get()
Methode mit mehreren Bedingungen bestanden? Im letzteren Szenario würde die Serviceschicht mehr von der logischen „Schwerarbeit“ übernehmen, wodurch der Data Mapper ziemlich einfach bleibt. Die erstere Option würde die Serviceschicht fast vollständig auf einen Mittelsmann reduzieren und die bedingte Logik in Methoden wie dem Data Mapper überlassen BookDataMapper->getByAuthorAndPublisher()
.
Die offensichtliche Sorge, die Serviceschicht die Bedingungen parsen zu lassen, besteht darin, dass ein Teil der Domänenlogik aus dem Data Mapper austritt. (Dies wird in der verknüpften Frage hier erklärt. Wenn jedoch die Serviceschicht die Bedingungen handhaben würde, würde die Logik die Modellschicht nicht verlassen. Der Controller würde anrufen $book_service->getByAuthorAndPublisher()
trotzdem.
Die Datenmapper Muster sagt Ihnen nur, was es tun soll, nicht wie es implementiert werden soll.
Daher sollten alle Antworten in diesem Thema als subjektiv behandelt werden, da sie die persönlichen Vorlieben jedes Autors widerspiegeln.
ich meistens Versuchen Sie, die Benutzeroberfläche des Mappers so einfach wie möglich zu halten:
fetch()
ruft Daten im Domänenobjekt oder der Sammlung ab,
save()
speichert (aktualisiert vorhandene oder fügt neue ein) das Domänenobjekt oder die Sammlung
remove()
löscht das Domänenobjekt oder die Sammlung vom Speichermedium
Ich behalte die Bedingung im Domänenobjekt selbst:
$user = new User;
$user->setName( 'Jedediah' );
$mapper = new UserMapper;
$mapper->fetch( $user );
if ( $user->getFlags() > 5 )
{
$user->setStatus( User::STATUS_LOCKED );
}
$mapper->save( $user );
Auf diese Weise können Sie mehrere Bedingungen für den Abruf haben und gleichzeitig die Schnittstelle sauber halten.
Der Nachteil dabei wäre, dass Sie eine öffentliche Methode zum Abrufen von Informationen aus dem Domänenobjekt benötigen, um eine solche zu haben fetch()
Methode, aber Sie werden es trotzdem brauchen, um es auszuführen save()
.
Es gibt keine wirkliche Möglichkeit, das zu implementieren “Sag, frag nicht” Faustregel für die Interaktion zwischen Mapper und Domänenobjekten.
Wie für “Wie stellen Sie sicher, dass Sie das Domänenobjekt wirklich speichern müssen?”die Ihnen einfallen könnten, wurde hier behandelt, mit ausführlichen Codebeispielen und einigen nützlichen Bits in den Kommentaren.
Aktualisieren
Wenn Sie erwarten, mit Gruppen von Objekten umzugehen, sollten Sie es mit unterschiedlichen Strukturen statt mit einfachen zu tun haben Domänenobjekte.
$category = new Category;
$category->setTitle( 'privacy' );
$list = new ArticleCollection;
$list->setCondition( $category );
$list->setDateRange( mktime( 0, 0, 0, 12, 9, 2001) );
// it would make sense, if unset second value for range of dates
// would default to NOW() in mapper
$mapper = new ArticleCollectionMapper;
$mapper->fetch( $list );
foreach ( $list as $article )
{
$article->setFlag( Article::STATUS_REMOVED );
}
$mapper->store( $list );
In diesem Fall ist die Sammlung ein verherrlichtes Array mit der Fähigkeit, verschiedene Parameter zu akzeptieren, die dann als Bedingungen für den Mapper verwendet werden. Es sollte auch den Mapper zu einer erworbenen Liste führen geändert Domänenobjekte aus dieser Sammlung, wenn der Mapper versucht, die Sammlung zu speichern.
Der Mapper sollte in diesem Fall in der Lage sein, Abfragen mit allen zu erstellen (oder voreingestellte zu verwenden). möglich Bedingungen (als Entwickler kennen Sie alle diese Bedingungen, daher müssen Sie es nicht mit einer unendlichen Menge von Bedingungen zum Laufen bringen) und aktualisieren oder erstellen Sie neue Einträge für alle nicht gespeicherten Domänenobjekte, die diese Sammlung enthält.
Notiz: In mancher Hinsicht könnte man sagen, dass die Mapper mit Builder/Factory-Mustern verwandt sind. Das Ziel ist ein anderes, aber der Ansatz zur Lösung der Probleme ist sehr ähnlich.
Normalerweise bevorzuge ich es, konkreter zu sein, wie:
BookDataMapper->getByAuthorAndPublisher($author, $publisher)
Das liegt daran, dass ich SQL nicht neu erfinden muss. Die Datenbank ist dafür besser geeignet und der Data-Mapper sorgt hier dafür, dass der Rest der Anwendung auch nichts darüber wissen muss, wie Dinge konkret gespeichert oder abgefragt werden.
Wenn Sie das dynamischer gestalten, können Sie leicht dazu neigen, zu viel Funktionalität über die Schnittstelle anzubieten. Nicht gut.
Und werfen Sie einen Blick auf Ihre Bewerbung. Sie werden sehen, dass nicht viel anders abgefragt werden muss. Für den Hauptteil der Daten sind das normalerweise etwa 5-10 Routinen, wenn überhaupt. Es ist viel schneller geschrieben, als auch nur an ein dynamisches System zu denken, das eigentlich sowieso in seine eigene Schicht gehören würde.