Xin chào các DEHAers!
Sau một thời gian làm việc với Laravel, hôm nay mình xin phép được chia sẻ với mọi người chút kiến thức mình tự tìm hiểu được về Repository Design Pattern và ứng dụng của nó trong Laravel Framework!
Menu
Repository Design Pattern là gì?
Đây là một mẫu thiết kế nâng cao mà các bạn mới tiếp xúc lập trình có lẽ cũng không để ý về nó lắm. Đối với các bạn đã có kinh nghiệm thực tập hay làm việc ở các công ty – chắc hẳn cũng đã được nghe các người hướng dẫn của mình nói về nó.
Repository Design Pattern là một trong những mẫu thiết kế được sử dụng nhiều nhất trong hầu hết các ngôn ngữ lập trình, các framework… như: .NET, Java, PHP…, trải dài từ websites, services, applications,… hay kể cả mobile apps.
Repository Design Pattern là một lớp trung gian giữa Business Logic và Data Source, các đối tượng trong lớp trung gian này được gọi là Repository. Giao tiếp giữa Business Logic và Data Source sẽ được thực hiện thông qua các Interface.
Chúng đem lại sự chuẩn hóa cho dữ liệu ra và tách biệt hoàn toàn việc xử lí business logic và data access logic, giúp cho Business Logic hoàn toàn không cần quan tâm tới công việc của Data Source (và ngược lại). Việc chia để trị này hướng tới mục tiêu: ai làm việc nấy, điều đó cũng khiến code của bạn sáng sủa hơn, rõ ràng hơn, và dễ bảo trì hơn.
Lợi ích của Repository Design Pattern:
- Code dễ phát triển và bảo trì khi làm việc theo nhóm.
- Giảm thiểu thay đổi code khi có thay đổi về cấu trúc dữ liệu, Data Source hoặc Business Logic.
- Business Logic và Data Source có thể test độc lập.
- Chuẩn hóa đầu ra dữ liệu.
- Giảm thiểu trùng lặp code (DRY – Don’t Repeat Yourself).
Những hạn chế:
- Viết nhiều, cái gì cũng phải nghĩ đến tách rời và đem xuống Repository và tái sử dụng.
- Dự án nhỏ thì không cần dùng cũng được.
- Với việc thế giới đang chuyển dần sang microservice thì việc áp dụng Repository Design Pattern cho mỗi mắt nhỏ trong microservice khá là dư thừa và tốn nhiều chi phí phát triển.
Repository Design Pattern và Laravel
Trong Laravel, Repository là “cây cầu” nối giữa Model và Controller, đây cũng là nơi tập trung xử lí các logic truy vấn dữ liệu.
Các truy vấn này trước đây được thực hiện trực tiếp ở Controller bây giờ sẽ được đưa vào Repository, lúc này Controller sẽ tương tác với Data Source thông qua Repository thay vì gọi trực tiếp Model. Việc thực hiện truy vấn như thế nào sẽ được Repository giấu kín bên trong (và Controller bản thân nó cũng chẳng cần quan tâm, cứ trả đúng – đủ dữ liệu về cho nó là được).
Thế còn phần xử lí Business Logic đâu rồi?
Trên thực tế, một số thao tác get dữ liệu đơn giản sẽ được gọi trực tiếp ở Controller thông qua Repository.
Đối với các business phức tạp sẽ có thêm một tầng Service ở giữa nữa. Có nghĩa là lúc này, Controller chỉ có trách nhiệm điều hướng xử lí logic xuống Service, và Service mới là nơi thực hiện các Business Logic và cập nhật xuống Data Source.
Triển khai Repository Design Pattern đơn giản cho Laravel
Hầu hết các hệ thống đều có phần User, nên mình sẽ lấy một ví dụ về User.
Trước tiên chúng ta sẽ xây dựng một UserModel.
<?php namespace App\Models; class User extends Model { /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'user_code', 'name', 'email' ]; }
Kế tiếp là UserController.
<?php namespace App\Http\Controllers; class UserController extends Controller { /** * Show list user * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ public function index() { $users = User::all(); return $users; } /** * Show info user * * @param $id * @return mixed */ public function show($id) { $user = User::findOrFail($id); return $user; } }
Trong UserController, User được gọi trực tiếp để truy vấn dữ liệu. Mọi chuyện đều êm đẹp cho tới khi khách hàng muốn thay đổi cách truy vấn dữ liệu: các User sẽ được sắp xếp theo user_code, và trang User Details được truy vấn bằng user_code thay vì id… Chắc chắn chúng ta sẽ cần phải cập nhật lại Controller để truy vấn dữ liệu cho phù hợp với requirements của khách hàng.
Điều này hết sức nguy hiểm và củ chuối. Bạn thử tưởng tượng không chỉ có mỗi UserController thực hiện các thao tác như thế này, mà rất nhiều Controller khác cũng thực hiện điều tương tự. Việc update code nhiều chỗ như vậy sẽ làm tăng khả năng bỏ sót hoặc thao tác sai lầm.
Và đây là lúc Repository phát huy tác dụng.
Chúng ta sẽ tạo một Repository như sau:
<?php namespace App\Repositories\User; class UserEloquentRepository { /** * Get list user with user_code * * @return mixed */ public function all() { return User::orderBy('user_code', 'desc')->all(); } /** * Get user by user code * * @param $id * @return mixed */ public function find($id) { return User::firstOrFail(['user_code' => $id]); } }
Cập nhật lại nội dung Controller
<?php namespace App\Http\Controllers; use App\Repositories\User\UserEloquentRepository; class UserController extends Controller { protected $userRepository; /** * UserController constructor. * @param UserEloquentRepository $userRepository */ public function __construct(UserEloquentRepository $userRepository) { $this->userRepository = $userRepository; } /** * Show list user * * @return mixed */ public function index() { $users = $this->userRepository->all(); return $users; } /** * Show info user * * @param $id * @return mixed */ public function show($id) { $user = $this->userRepository->find($id); return $user; } }
Vậy là từ giờ trở đi, bạn cần thêm logic gì cứ vào Repository mà sửa, rõ ràng – sạch sẽ – khô thoáng – dễ hiểu!
Bài viết xin phép được kết thúc tại đây, có nội dung nào chưa chính xác xin mọi người góp ý vào comment bên dưới!
Cám ơn các bạn đã theo dõi.
Bài viết có tham khảo trên google search và facebook search.