Laravel의 리포지토리 패턴(Repository)의 장점에 대한 간략한 분석
왜 Laravel에서 저장소 패턴(Repository)을 사용하나요? 다음 글에서는 저장소 모드 사용의 장점을 소개하겠습니다. 도움이 되길 바랍니다.
이전 글에서는 저장소 패턴이 무엇인지, Active Record 패턴과 어떻게 다른지, Laravel에서 구현하는 방법에 대해 설명했습니다. 이제 저장소 패턴을 사용해야 하는 이유를 자세히 살펴보겠습니다.
이전 게시물의 댓글에서 Repository 패턴이 Laravel 커뮤니티에서 논란이 되는 주제라는 것을 알아냈습니다. 어떤 사람들은 사용할 이유가 없다고 생각하고 내장된 Active Record 모드를 고수합니다. 다른 사람들은 논리적 도메인에서 데이터 액세스를 분리하기 위해 다른 방법을 사용하는 것을 선호합니다. 나는 이러한 의견을 존중하며 이 주제에 대해 향후 블로그 게시물을 작성할 예정입니다.
이 고지 사항을 통해 저장소 패턴 사용의 이점을 이해해 보겠습니다.
단일 책임 원칙
단일 책임 원칙은 Active Record 패턴과 Repository 패턴을 구별하는 주요 판별자입니다. 모델 클래스는 이미 데이터를 보유하고 도메인 개체에 대한 메서드를 제공합니다. Active Record 패턴을 사용하면 데이터 액세스에 대한 추가 책임이 발생합니다. 이는 다음 예에서 설명하고 싶은 내용입니다.
/** * @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();
도메인 모델과 데이터 액세스 기술의 책임이 혼합되어 있지만 직관적으로 이해됩니다. 우리 애플리케이션에서는 직원이 어떻게든 데이터베이스에 저장되어야 하므로 객체에 대해 save()
를 호출하는 것은 어떨까요? 단일 객체는 단일 데이터 행으로 변환되어 저장됩니다. save()
。单个对象被转化成单个数据行并存储。
但是,让我们更进一步,看看我们还能对员工做些什么:
$jack->where('first_name', 'John')->firstOrFail()->delete(); $competition = $jack->where('company_id', $facebookId)->get();
现在,它变得不直观,甚至违背了我们的域模型。 为什么 Jack 会突然删除另一个甚至可能在不同公司工作的员工? 或者他为什么能把 Facebook 的员工拉过来?
当然,这个例子是人为设计的,但它仍然显示了 Active Record 模式如何不允许有意的域模型。 员工与所有员工列表之间的界限变得模糊。 您始终必须考虑该员工是被用作实际员工还是作为访问其他员工的机制。
仓库模式通过强制执行这个基本分区来解决这个问题。它的唯一用途是标识域对象的合集,而不是域对象的本身。
要点:
- 通过将所有域对象的集合与单个域对象分离, 仓库模式体现了单一责任原则 。
不要重复自己 (DRY)
一些项目将数据库查询洒遍了整个项目。下面是一个例子,我们从数据库中获取列表,并在 Blade 视图中显示他们。
class InvoiceController { public function index(): View { return view('invoices.index', [ 'invoices' => Invoice::where('overdue_since', '>=', Carbon::now()) ->orderBy('overdue_since') ->paginate() ]); } }
当这样的查询遍得更加复杂并且在多个地方使用时,考虑将其提取到 Repository 方法中。
存储库模式通过将重复查询打包到表达方法中来帮助减少重复查询。如果必须调整查询,只需更改一次即可。
class InvoiceController { public __construct(private InvoiceRepository $repo) {} public function index(): View { return view('invoices.index', [ 'invoices' => $repo->paginateOverdueInvoices() ]); } }
现在查询只实现一次,可以单独测试并在其他地方使用。此外,单一责任原则再次发挥作用,因为控制器不负责获取数据,而只负责处理HTTP请求和返回响应。
Takeaway:
- ? 存储库模式有助于减少重复查询
依赖反转
解释 Dependency Inversion Principle 值得发表自己的博客文章。我只是想说明存储库可以启用依赖项反转。
在对组件进行分层时,通常较高级别的组件依赖于较低级别的组件。 例如,控制器将依赖模型类从数据库中获取数据:
class InvoiceController { public function index(int $companyId): View { return view( 'invoices.index', ['invoices' => Invoice::where('company_id', $companyId)->get()] ); } }
依赖关系是自上而下的,紧密耦合的。 InvoiceController
取决于具体的 Invoice
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 查询构造器实现该方法 } }
Warehouse 모드는 기본 파티셔닝을 적용하여 이 문제를 해결합니다. 유일한 목적은 도메인 개체 자체가 아닌 도메인 개체 모음을 식별하는 것입니다.
🎜🎜🎜핵심 사항:🎜🎜🎜🎜모든 도메인 개체 컬렉션을 단일 도메인 개체에서 분리함으로써 🎜웨어하우스 패턴은 단일 책임 원칙🎜을 구현합니다. 🎜🎜🎜🎜반복하지 마세요(DRY)🎜🎜🎜일부 프로젝트에서는 프로젝트 전체에 데이터베이스 쿼리를 뿌립니다. 다음은 데이터베이스에서 목록을 가져와 블레이드 보기에 표시하는 예입니다. 🎜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(); );
class InMemoryInvoiceRepository implements InvoiceRepositoryInterface { private array $invoices; // implement the methods by accessing $this->invoices... } // --- Test Case: $repo = new InMemoryInvoiceRepository(); $service = new InvoiceService($repo);
$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);
InvoiceController
는 특정 Invoice
클래스에 따라 다릅니다. 별도로 테스트하거나 저장 메커니즘을 교체하는 등 이 두 클래스를 분리하는 것은 어렵습니다. Repository 인터페이스를 도입함으로써 우리는 종속성 반전을 달성할 수 있습니다. 🎜rrreee🎜Controller는 이제 Repository 구현과 마찬가지로 Repository 인터페이스에만 의존합니다. 🎜이 두 클래스는 이제 하나의 추상화에만 의존하므로 설명하겠습니다. 다음 섹션에서 🎜🎜🎜테이크아웃:🎜🎜에 설명된 대로 추가 이점을 제공합니다.- ? 存储库模式作为一种抽象类,支持依赖反转.
抽象类
存储库 提高了可读性 因为复杂的操作被具有表达性名称的高级方法隐藏了.
访问存储库的代码与底层数据访问技术分离. 如有必要,您可以切换实现,甚至可以省略实现,仅提供 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(); );
要点:
- ? 存储库模式抽象了有关数据访问的详细信息。
- ? 存储库将客户端与数据访问技术分离。
- ? 这允许切换实现,提高可读性并实现可组合性。
可测试性
存储库模式提供的抽象也有助于测试。
如果你有一个 Repository 接口,你可以提供一个替代的测试实现。 您可以使用数组支持存储库,而不是访问数据库,将所有对象保存在数组中:
class InMemoryInvoiceRepository implements InvoiceRepositoryInterface { private array $invoices; // implement the methods by accessing $this->invoices... } // --- Test Case: $repo = new InMemoryInvoiceRepository(); $service = new InvoiceService($repo);
通过这种方法,您将获得一个现实的实现,它速度很快并且在内存中运行。 但是您必须为测试提供正确的 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);
有了 mock,测试用例就是一个适当的单元测试。上面示例中测试的唯一代码是服务。没有数据库访问,这使得测试用例的设置和运行非常快速。
另外:
- ? 仓库模式允许进行适当的单元测试,这些单元测试运行快并且是隔离的。
原文地址:https://dev.to/davidrjenni/why-use-the-repository-pattern-in-laravel-2j1m
译文地址:https://learnku.com/laravel/t/62521
【相关推荐:laravel视频教程】
위 내용은 Laravel의 리포지토리 패턴(Repository)의 장점에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Laraveleloquent 모델 검색 : 데이터베이스 데이터를 쉽게 얻을 수 있습니다. 이 기사는 데이터베이스에서 데이터를 효율적으로 얻는 데 도움이되는 다양한 웅변 모델 검색 기술을 자세히 소개합니다. 1. 모든 기록을 얻으십시오. 모든 () 메소드를 사용하여 데이터베이스 테이블에서 모든 레코드를 가져옵니다. 이것은 컬렉션을 반환합니다. Foreach 루프 또는 기타 수집 방법을 사용하여 데이터에 액세스 할 수 있습니다 : Foreach ($ postas $ post) {echo $ post->

PHP의 미래는 새로운 기술 트렌드에 적응하고 혁신적인 기능을 도입함으로써 달성 될 것입니다. 1) 클라우드 컴퓨팅, 컨테이너화 및 마이크로 서비스 아키텍처에 적응, Docker 및 Kubernetes 지원; 2) 성능 및 데이터 처리 효율을 향상시키기 위해 JIT 컴파일러 및 열거 유형을 도입합니다. 3) 지속적으로 성능을 최적화하고 모범 사례를 홍보합니다.

7 백만 레코드를 효율적으로 처리하고 지리 공간 기술로 대화식지도를 만듭니다. 이 기사는 Laravel과 MySQL을 사용하여 7 백만 개 이상의 레코드를 효율적으로 처리하고 대화식지도 시각화로 변환하는 방법을 살펴 봅니다. 초기 챌린지 프로젝트 요구 사항 : MySQL 데이터베이스에서 7 백만 레코드를 사용하여 귀중한 통찰력을 추출합니다. 많은 사람들이 먼저 프로그래밍 언어를 고려하지만 데이터베이스 자체를 무시합니다. 요구 사항을 충족시킬 수 있습니까? 데이터 마이그레이션 또는 구조 조정이 필요합니까? MySQL이 큰 데이터로드를 견딜 수 있습니까? 예비 분석 : 주요 필터 및 속성을 식별해야합니다. 분석 후, 몇 가지 속성만이 솔루션과 관련이 있음이 밝혀졌습니다. 필터의 타당성을 확인하고 검색을 최적화하기위한 제한 사항을 설정했습니다. 도시를 기반으로 한지도 검색

PHP와 Python은 각각 고유 한 장점이 있으며 선택은 프로젝트 요구 사항을 기반으로해야합니다. 1.PHP는 간단한 구문과 높은 실행 효율로 웹 개발에 적합합니다. 2. Python은 간결한 구문 및 풍부한 라이브러리를 갖춘 데이터 과학 및 기계 학습에 적합합니다.

PHP와 Python은 각각 고유 한 장점이 있으며 프로젝트 요구 사항에 따라 선택합니다. 1.PHP는 웹 개발, 특히 웹 사이트의 빠른 개발 및 유지 보수에 적합합니다. 2. Python은 간결한 구문을 가진 데이터 과학, 기계 학습 및 인공 지능에 적합하며 초보자에게 적합합니다.

PHP는 현대 웹 개발, 특히 컨텐츠 관리 및 전자 상거래 플랫폼에서 중요합니다. 1) PHP는 Laravel 및 Symfony와 같은 풍부한 생태계와 강력한 프레임 워크 지원을 가지고 있습니다. 2) Opcache 및 Nginx를 통해 성능 최적화를 달성 할 수 있습니다. 3) PHP8.0은 성능을 향상시키기 위해 JIT 컴파일러를 소개합니다. 4) 클라우드 네이티브 애플리케이션은 Docker 및 Kubernetes를 통해 배포되어 유연성과 확장 성을 향상시킵니다.

Laravel은 백엔드 논리에서 어떻게 중요한 역할을합니까? 라우팅 시스템, eloquentorm, 인증 및 승인, 이벤트 및 청취자, 성능 최적화를 통해 백엔드 개발을 단순화하고 향상시킵니다. 1. 라우팅 시스템은 URL 구조의 정의 및 요청 처리 로직을 정의 할 수 있습니다. 2. eloquentorm은 데이터베이스 상호 작용을 단순화합니다. 3. 인증 및 인증 시스템은 사용자 관리에 편리합니다. 4. 이벤트와 리스너는 느슨하게 결합 된 코드 구조를 구현합니다. 5. 성능 최적화는 캐싱 및 대기열을 통한 응용 프로그램 효율성을 향상시킵니다.

PHP가 많은 웹 사이트에서 선호되는 기술 스택 인 이유에는 사용 편의성, 강력한 커뮤니티 지원 및 광범위한 사용이 포함됩니다. 1) 배우고 사용하기 쉽고 초보자에게 적합합니다. 2) 거대한 개발자 커뮤니티와 풍부한 자원이 있습니다. 3) WordPress, Drupal 및 기타 플랫폼에서 널리 사용됩니다. 4) 웹 서버와 밀접하게 통합하여 개발 배포를 단순화합니다.
