Inhaltsverzeichnis
Prinzip der Einzelverantwortung
不要重复自己 (DRY)" >不要重复自己 (DRY)
依赖反转
抽象类" >抽象类
可测试性
Heim PHP-Framework Laravel Eine kurze Analyse der Vorteile des Repository-Musters (Repository) in Laravel

Eine kurze Analyse der Vorteile des Repository-Musters (Repository) in Laravel

Dec 05, 2022 pm 07:20 PM
php laravel

Warum das Repository-Muster (Repository) in Laravel verwenden? Der folgende Artikel stellt Ihnen die Vorteile der Verwendung des Repository-Modus vor. Ich hoffe, er wird Ihnen hilfreich sein!

Eine kurze Analyse der Vorteile des Repository-Musters (Repository) in Laravel

In meinem vorherigen Artikel habe ich erklärt, was das Repository-Muster ist, wie es sich vom Active Record-Muster unterscheidet und wie man es in Laravel implementiert. Jetzt möchte ich näher darauf eingehen, warum Sie das Repository-Muster verwenden sollten.

Mir ist in den Kommentaren des vorherigen Beitrags aufgefallen, dass das Repository-Muster ein kontroverses Thema in der Laravel-Community ist. Manche Leute sehen keinen Grund, es zu verwenden und bleiben beim integrierten Active Record-Modus. Andere bevorzugen andere Methoden, um den Datenzugriff von der logischen Domäne zu trennen. Bitte beachten Sie, dass ich diese Meinungen respektiere und diesem Thema einen kommenden Blogbeitrag widmen werde.

Mit diesem Haftungsausschluss wollen wir die Vorteile der Verwendung des Repository-Musters verstehen.

Prinzip der Einzelverantwortung

Das Prinzip der Einzelverantwortung ist das Hauptunterscheidungsmerkmal zur Unterscheidung zwischen Active Record-Muster und Repository-Muster. Modellklassen enthalten bereits Daten und stellen Methoden für Domänenobjekte bereit. Bei Verwendung des Active Record-Musters ist der Datenzugriff eine zusätzliche Verantwortung, die eingeführt wird. Dies möchte ich an folgendem Beispiel veranschaulichen:

/**
 * @property string $first_name
 * @property int    $company_id
 */
class Employee extends Model {}

$jack = new Employee();
$jack->first_name = 'Jack';
$jack->company_id = $twitterId;
$jack->save();
Nach dem Login kopieren

Obwohl das Domänenmodell und die Datenzugriffstechnologie gemischte Verantwortlichkeiten haben, ergibt es intuitiv Sinn. In unserer Anwendung müssen die Mitarbeiter irgendwie in der Datenbank gespeichert werden. Warum also nicht save() für das Objekt aufrufen? Ein einzelnes Objekt wird in eine einzelne Datenzeile umgewandelt und gespeichert. save()。单个对象被转化成单个数据行并存储。

但是,让我们更进一步,看看我们还能对员工做些什么:

$jack->where('first_name', 'John')->firstOrFail()->delete();
$competition = $jack->where('company_id', $facebookId)->get();
Nach dem Login kopieren

现在,它变得不直观,甚至违背了我们的域模型。 为什么 Jack 会突然删除另一个甚至可能在不同公司工作的员工? 或者他为什么能把 Facebook 的员工拉过来?

当然,这个例子是人为设计的,但它仍然显示了 Active Record 模式如何不允许有意的域模型。 员工与所有员工列表之间的界限变得模糊。 您始终必须考虑该员工是被用作实际员工还是作为访问其他员工的机制。

仓库模式通过强制执行这个基本分区来解决这个问题。它的唯一用途是标识域对象的合集,而不是域对象的本身。

要点:

  • 通过将所有域对象的集合与单个域对象分离, 仓库模式体现了单一责任原则

一些项目将数据库查询洒遍了整个项目。下面是一个例子,我们从数据库中获取列表,并在 Blade 视图中显示他们。

class InvoiceController {

    public function index(): View {
        return view('invoices.index', [
            'invoices' => Invoice::where('overdue_since', '>=', Carbon::now())
                ->orderBy('overdue_since')
                ->paginate()
        ]);
    }
}
Nach dem Login kopieren

当这样的查询遍得更加复杂并且在多个地方使用时,考虑将其提取到 Repository 方法中。

存储库模式通过将重复查询打包到表达方法中来帮助减少重复查询。如果必须调整查询,只需更改一次即可。

class InvoiceController {

    public __construct(private InvoiceRepository $repo) {}

    public function index(): View {
        return view('invoices.index', [
            'invoices' => $repo->paginateOverdueInvoices()
        ]);
    }
}
Nach dem Login kopieren

现在查询只实现一次,可以单独测试并在其他地方使用。此外,单一责任原则再次发挥作用,因为控制器不负责获取数据,而只负责处理HTTP请求和返回响应。

Takeaway:

  • ? 存储库模式有助于减少重复查询

依赖反转

解释 Dependency Inversion Principle 值得发表自己的博客文章。我只是想说明存储库可以启用依赖项反转。

在对组件进行分层时,通常较高级别的组件依赖于较低级别的组件。 例如,控制器将依赖模型类从数据库中获取数据:

class InvoiceController {
    public function index(int $companyId): View {
        return view(
            'invoices.index',
            ['invoices' => Invoice::where('company_id', $companyId)->get()]
        );
    }
}
Nach dem Login kopieren

依赖关系是自上而下的,紧密耦合的。 InvoiceController 取决于具体的 Invoice

Aber gehen wir noch einen Schritt weiter und sehen, was wir sonst noch mit Mitarbeitern machen können:

interface InvoiceRepository {
    public function findByCompanyId($companyId): Collection;
}

class InvoiceController {
    public function __construct(private InvoiceRepository $repo) {}

    public function index(int $companyId): View {
        return view(
            'invoices.index',
            ['invoices' => $this->repo->findByCompanyId($companyId)]
        );
    }
}

class EloquentInvoiceRepository implements InvoiceRepository {
    public function findByCompanyId($companyId): Collection {
        // 使用 Eloquent 查询构造器实现该方法
    }
}
Nach dem Login kopieren
Jetzt wird es unintuitiv und widerspricht sogar unserem Domänenmodell. Warum sollte Jack plötzlich einen anderen Mitarbeiter löschen, der vielleicht sogar bei einem anderen Unternehmen arbeitet? Oder warum konnte er Facebook-Mitarbeiter herbeiholen?

Natürlich ist dieses Beispiel gekünstelt, aber es zeigt dennoch, dass das Active Record-Muster keine absichtliche Domänenmodellierung zulässt. Die Grenze zwischen Mitarbeitern und der Liste aller Mitarbeiter verschwimmt. Es muss immer berücksichtigt werden, ob der Mitarbeiter als tatsächlicher Mitarbeiter oder als Mechanismus für den Zugriff auf andere Mitarbeiter genutzt wird.

Der Warehouse-Modus löst dieses Problem, indem er diese grundlegende Partitionierung erzwingt. Der einzige Zweck besteht darin, eine Sammlung von Domänenobjekten zu identifizieren, nicht die Domänenobjekte selbst.

🎜🎜🎜Wichtige Punkte:🎜🎜🎜🎜Durch die Entkopplung einer Sammlung aller Domänenobjekte von einem einzelnen Domänenobjekt 🎜Das Warehouse-Muster verkörpert das Prinzip der Einzelverantwortung🎜. 🎜🎜🎜🎜Don't Repeat Yourself (DRY)🎜🎜🎜Einige Projekte verteilen Datenbankabfragen über das gesamte Projekt. Unten sehen Sie ein Beispiel, in dem wir Listen aus der Datenbank abrufen und sie in einer Blade-Ansicht anzeigen. 🎜
interface InvoiceRepository {
    public function findById(int $id): Invoice;
}

class InvoiceCacheRepository implements InvoiceRepository {

    public function __construct(
        private InvoiceRepository $repo,
        private int $ttlSeconds
    ) {}

    public function findById(int $id): Invoice {
        return Cache::remember(
            "invoice.$id",
            $this->ttlSeconds,
            fn(): Invoice => $this->repo->findById($id)
        );
    }
}

class EloquentInvoiceRepository implements InvoiceRepository {

    public function findById(int $id): Invoice { /* 从数据库中取出 $id */ }
}

// --- 用法:

$repo = new InvoiceCacheRepository(
    new EloquentInvoiceRepository();
);
Nach dem Login kopieren
Nach dem Login kopieren
🎜Wenn eine Abfrage wie diese komplexer wird und an mehreren Stellen verwendet wird, sollten Sie erwägen, sie in eine Repository-Methode zu extrahieren. 🎜🎜Das Repository-Muster trägt dazu bei, doppelte Abfragen zu reduzieren, indem es sie in Ausdrucksmethoden verpackt. Wenn Sie die Abfrage anpassen müssen, müssen Sie diese nur einmal ändern. 🎜
class InMemoryInvoiceRepository implements InvoiceRepositoryInterface {

    private array $invoices;

    // implement the methods by accessing $this->invoices...
}

// --- Test Case:

$repo = new InMemoryInvoiceRepository();
$service = new InvoiceService($repo);
Nach dem Login kopieren
Nach dem Login kopieren
🎜Jetzt werden Abfragen nur einmal implementiert und können isoliert getestet und an anderer Stelle verwendet werden. Darüber hinaus kommt wieder das Single-Responsibility-Prinzip zum Tragen, da der Verantwortliche nicht für den Erhalt der Daten verantwortlich ist, sondern nur für die Verarbeitung der HTTP-Anfrage und die Rücksendung der Antwort. 🎜🎜🎜Takeaway:🎜🎜🎜🎜? Repository-Muster hilft, doppelte Abfragen zu reduzieren 🎜🎜🎜🎜Abhängigkeitsumkehr 🎜🎜🎜Erklärung Abhängigkeitsinversionsprinzip🎜 verdient einen eigenen Blogbeitrag. Ich wollte nur veranschaulichen, dass ein Repository eine Abhängigkeitsumkehr ermöglichen kann. 🎜🎜Bei der Schichtung von Komponenten hängen Komponenten höherer Ebenen normalerweise von Komponenten niedrigerer Ebenen ab. Beispielsweise verlässt sich der Controller auf die Modellklasse, um Daten aus der Datenbank abzurufen: 🎜
$companyId = 42;

/** @var InvoiceRepository&MockObject */
$repo = $this->createMock(InvoiceRepository::class);

$repo->expects($this->once())
    ->method('findInvoicedToCompany')
    ->with($companyId)
    ->willReturn(collect([ /* invoices to return in the test case */ ]));

$service = new InvoiceService($repo);

$result = $service->calculateAvgInvoiceAmount($companyId);

$this->assertEquals(1337.42, $result);
Nach dem Login kopieren
Nach dem Login kopieren
🎜Die Abhängigkeit ist von oben nach unten und eng gekoppelt. InvoiceController hängt von der spezifischen Invoice-Klasse ab. Es ist schwierig, diese beiden Klassen zu entkoppeln, indem man sie beispielsweise separat testet oder den Speichermechanismus ersetzt. Durch die Einführung der Repository-Schnittstelle können wir eine Abhängigkeitsumkehr erreichen: 🎜rrreee🎜Controller hängt jetzt nur noch von der Repository-Schnittstelle ab, genau wie die Repository-Implementierung 🎜Diese beiden Klassen hängen jetzt nur noch von einer Abstraktion ab, wodurch die Kopplung reduziert wird im nächsten Abschnitt Dies bringt weitere Vorteile mit sich, wie in 🎜🎜🎜Takeaway:🎜🎜 erläutert
  • ? 存储库模式作为一种抽象类,支持依赖反转.

存储库 提高了可读性 因为复杂的操作被具有表达性名称的高级方法隐藏了.

访问存储库的代码与底层数据访问技术分离. 如有必要,您可以切换实现,甚至可以省略实现,仅提供 Repository 接口。 这对于旨在与框架无关的库来说非常方便。

OAuth2 服务包 —— league/oauth2-server 也用到这个抽象类机制。 Laravel Passport 也通过 实现这个库的接口 集成 league/oauth2-server 包。

正如 @bdelespierre评论 里回应我之前的一篇博客文章时向我指出的那样,你不仅可以切换存储库实现,还可以将它们组合在一起。大致以他的示例为基础,您可以看到一个存储库如何包装另一个存储库以提供附加功能:

interface InvoiceRepository {
    public function findById(int $id): Invoice;
}

class InvoiceCacheRepository implements InvoiceRepository {

    public function __construct(
        private InvoiceRepository $repo,
        private int $ttlSeconds
    ) {}

    public function findById(int $id): Invoice {
        return Cache::remember(
            "invoice.$id",
            $this->ttlSeconds,
            fn(): Invoice => $this->repo->findById($id)
        );
    }
}

class EloquentInvoiceRepository implements InvoiceRepository {

    public function findById(int $id): Invoice { /* 从数据库中取出 $id */ }
}

// --- 用法:

$repo = new InvoiceCacheRepository(
    new EloquentInvoiceRepository();
);
Nach dem Login kopieren
Nach dem Login kopieren

要点:

  • ? 存储库模式抽象了有关数据访问的详细信息。
  • ? 存储库将客户端与数据访问技术分离
  • ? 这允许切换实现,提高可读性并实现可组合性。

可测试性

存储库模式提供的抽象也有助于测试。

如果你有一个 Repository 接口,你可以提供一个替代的测试实现。 您可以使用数组支持存储库,而不是访问数据库,将所有对象保存在数组中:

class InMemoryInvoiceRepository implements InvoiceRepositoryInterface {

    private array $invoices;

    // implement the methods by accessing $this->invoices...
}

// --- Test Case:

$repo = new InMemoryInvoiceRepository();
$service = new InvoiceService($repo);
Nach dem Login kopieren
Nach dem Login kopieren

通过这种方法,您将获得一个现实的实现,它速度很快并且在内存中运行。 但是您必须为测试提供正确的 Repository 实现,这 ** 本身可能需要大量工作**。 在我看来,这在两种情况下是合理的:

  • 您正在开发一个(与框架无关的)库,它本身不提供存储库实现。

  • 测试用例复杂,Repository 的状态很重要。

另一种方法是“模仿”,要使用这种技术,你不需要适当的接口。你可以模仿任何 non-final 类。
使用 PHPUnit API ,您可以明确规定如何调用存储库以及应该返回什么。

$companyId = 42;

/** @var InvoiceRepository&MockObject */
$repo = $this->createMock(InvoiceRepository::class);

$repo->expects($this->once())
    ->method('findInvoicedToCompany')
    ->with($companyId)
    ->willReturn(collect([ /* invoices to return in the test case */ ]));

$service = new InvoiceService($repo);

$result = $service->calculateAvgInvoiceAmount($companyId);

$this->assertEquals(1337.42, $result);
Nach dem Login kopieren
Nach dem Login kopieren

有了 mock,测试用例就是一个适当的单元测试。上面示例中测试的唯一代码是服务。没有数据库访问,这使得测试用例的设置和运行非常快速

另外:

  • ? 仓库模式允许进行适当的单元测试,这些单元测试运行快并且是隔离的

原文地址:https://dev.to/davidrjenni/why-use-the-repository-pattern-in-laravel-2j1m

译文地址:https://learnku.com/laravel/t/62521

【相关推荐:laravel视频教程

Das obige ist der detaillierte Inhalt vonEine kurze Analyse der Vorteile des Repository-Musters (Repository) in Laravel. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat -Befehle und wie man sie benutzt
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

PHP 8.4 Installations- und Upgrade-Anleitung für Ubuntu und Debian PHP 8.4 Installations- und Upgrade-Anleitung für Ubuntu und Debian Dec 24, 2024 pm 04:42 PM

PHP 8.4 bringt mehrere neue Funktionen, Sicherheitsverbesserungen und Leistungsverbesserungen mit einer beträchtlichen Menge an veralteten und entfernten Funktionen. In dieser Anleitung wird erklärt, wie Sie PHP 8.4 installieren oder auf PHP 8.4 auf Ubuntu, Debian oder deren Derivaten aktualisieren. Obwohl es möglich ist, PHP aus dem Quellcode zu kompilieren, ist die Installation aus einem APT-Repository wie unten erläutert oft schneller und sicherer, da diese Repositorys in Zukunft die neuesten Fehlerbehebungen und Sicherheitsupdates bereitstellen.

So richten Sie Visual Studio-Code (VS-Code) für die PHP-Entwicklung ein So richten Sie Visual Studio-Code (VS-Code) für die PHP-Entwicklung ein Dec 20, 2024 am 11:31 AM

Visual Studio Code, auch bekannt als VS Code, ist ein kostenloser Quellcode-Editor – oder eine integrierte Entwicklungsumgebung (IDE) –, die für alle gängigen Betriebssysteme verfügbar ist. Mit einer großen Sammlung von Erweiterungen für viele Programmiersprachen kann VS Code c

Wie analysiert und verarbeitet man HTML/XML in PHP? Wie analysiert und verarbeitet man HTML/XML in PHP? Feb 07, 2025 am 11:57 AM

Dieses Tutorial zeigt, wie XML -Dokumente mit PHP effizient verarbeitet werden. XML (Extensible Markup-Sprache) ist eine vielseitige textbasierte Markup-Sprache, die sowohl für die Lesbarkeit des Menschen als auch für die Analyse von Maschinen entwickelt wurde. Es wird üblicherweise für die Datenspeicherung ein verwendet und wird häufig verwendet

Erklären Sie JSON Web Tokens (JWT) und ihren Anwendungsfall in PHP -APIs. Erklären Sie JSON Web Tokens (JWT) und ihren Anwendungsfall in PHP -APIs. Apr 05, 2025 am 12:04 AM

JWT ist ein offener Standard, der auf JSON basiert und zur sicheren Übertragung von Informationen zwischen Parteien verwendet wird, hauptsächlich für die Identitätsauthentifizierung und den Informationsaustausch. 1. JWT besteht aus drei Teilen: Header, Nutzlast und Signatur. 2. Das Arbeitsprinzip von JWT enthält drei Schritte: Generierung von JWT, Überprüfung von JWT und Parsingnayload. 3. Bei Verwendung von JWT zur Authentifizierung in PHP kann JWT generiert und überprüft werden, und die Funktionen und Berechtigungsinformationen der Benutzer können in die erweiterte Verwendung aufgenommen werden. 4. Häufige Fehler sind Signaturüberprüfungsfehler, Token -Ablauf und übergroße Nutzlast. Zu Debugging -Fähigkeiten gehört die Verwendung von Debugging -Tools und Protokollierung. 5. Leistungsoptimierung und Best Practices umfassen die Verwendung geeigneter Signaturalgorithmen, das Einstellen von Gültigkeitsperioden angemessen.

PHP -Programm zum Zählen von Vokalen in einer Zeichenfolge PHP -Programm zum Zählen von Vokalen in einer Zeichenfolge Feb 07, 2025 pm 12:12 PM

Eine Zeichenfolge ist eine Folge von Zeichen, einschließlich Buchstaben, Zahlen und Symbolen. In diesem Tutorial wird lernen, wie Sie die Anzahl der Vokale in einer bestimmten Zeichenfolge in PHP unter Verwendung verschiedener Methoden berechnen. Die Vokale auf Englisch sind a, e, i, o, u und sie können Großbuchstaben oder Kleinbuchstaben sein. Was ist ein Vokal? Vokale sind alphabetische Zeichen, die eine spezifische Aussprache darstellen. Es gibt fünf Vokale in Englisch, einschließlich Großbuchstaben und Kleinbuchstaben: a, e, ich, o, u Beispiel 1 Eingabe: String = "TutorialPoint" Ausgabe: 6 erklären Die Vokale in der String "TutorialPoint" sind u, o, i, a, o, ich. Insgesamt gibt es 6 Yuan

Erklären Sie die späte statische Bindung in PHP (statisch: :). Erklären Sie die späte statische Bindung in PHP (statisch: :). Apr 03, 2025 am 12:04 AM

Statische Bindung (statisch: :) implementiert die späte statische Bindung (LSB) in PHP, sodass das Aufrufen von Klassen in statischen Kontexten anstatt Klassen zu definieren. 1) Der Analyseprozess wird zur Laufzeit durchgeführt.

Was sind PHP Magic -Methoden (__construct, __Destruct, __call, __get, __set usw.) und geben Sie Anwendungsfälle an? Was sind PHP Magic -Methoden (__construct, __Destruct, __call, __get, __set usw.) und geben Sie Anwendungsfälle an? Apr 03, 2025 am 12:03 AM

Was sind die magischen Methoden von PHP? Zu den magischen Methoden von PHP gehören: 1. \ _ \ _ Konstrukt, verwendet, um Objekte zu initialisieren; 2. \ _ \ _ Destruct, verwendet zur Reinigung von Ressourcen; 3. \ _ \ _ Call, behandeln Sie nicht existierende Methodenaufrufe; 4. \ _ \ _ GET, Implementieren Sie den dynamischen Attributzugriff; 5. \ _ \ _ Setzen Sie dynamische Attributeinstellungen. Diese Methoden werden in bestimmten Situationen automatisch aufgerufen, wodurch die Code -Flexibilität und -Effizienz verbessert werden.

Wie bekomme ich den Rückgabecode, wenn das Senden von E -Mails in Laravel fehlschlägt? Wie bekomme ich den Rückgabecode, wenn das Senden von E -Mails in Laravel fehlschlägt? Apr 01, 2025 pm 02:45 PM

Methode zum Abholen des Rücksendecode, wenn das Senden von Laravel -E -Mails fehlschlägt. Wenn Sie Laravel zur Entwicklung von Anwendungen verwenden, stellen Sie häufig Situationen auf, in denen Sie Überprüfungscodes senden müssen. Und in Wirklichkeit ...

See all articles