Áp dụng Specification Design Pattern trong Laravel

Tram Ho

Là một lập trình viên, chắc hẳn mỗi chúng ta đều không xa lạ với khái niệm Design Pattern. Đó là các mẫu thiết kế chuẩn, những khuôn mẫu cho các vấn đề chung trong thiết kế phần mềm. Trong bài viết này, mình sẽ giới thiệu một design pattern phổ biến – Specification và cách triển khai nó trong Laravel.

1. Specification Design Pattern là gì?

Specification pattern là một mẫu thiết kế, theo đó các quy tắc nghiệp vụ có thể được kết hợp lại bằng cách xâu chuỗi. Mỗi specification có một rule cần phải tuân theo. Specification cho phép chúng ta đóng gói một vài thông tin về nghiệp vụ vào trong một đơn vị code và có thể sử dụng lại chúng trong những chỗ khác nhau, giúp cho code của chúng ta tăng tính sử dụng lại và dễ đọc hiểu, dễ bảo trì hơn.

Cách tiếp cận này không chỉ giúp loại bỏ nghiệp vụ bị trùng lặp, nó cũng cho phép kết hợp nhiều các nghiệp vụ lại bởi nhiều Specification. Giúp cho việc dễ dàng cài đặt các điều kiện tìm kiếm phức tạp và kiểm tra dữ liệu. Có 3 trường hợp chính sử dụng Specification Pattern:

  • Tìm kiếm dữ liệu trong DB. Tìm kiếm các bản ghi thỏa mãn với điều kiện.
  • Kiểm tra các đối tượng trong bộ nhớ. Nói cách khác, kiểm tra xem một đối tượng có phù hợp với điều kiện không
  • Tạo mới một thể hiện thỏa mãn điều kiện.

image.png

Giả sử ta có một bài toán truy xuất các hóa đơn và gửi chúng đến cơ quan thu nợ nếu ba điều kiện sau được thỏa mãn: (1) hóa đơn đã quá hạn, (2) thông báo quá hạn đã được gửi đi, (3) hóa đơn chưa được gửi đến cơ quan thu nợ. Ví dụ này nhằm cho thấy kết quả cuối cùng về cách các logic nghiệp vụ được ‘xâu chuỗi’ lại với nhau. Ta hoàn toàn có thể viết một phương thức check điều kiện có gửi hóa đơn đến cơ quan thu nợ trong lớp model Invoice. Tuy nhiên, việc viết như vậy vi phạm nguyên lý Single Responsibility trong SOLID, hơn nữa lại không thể tái sử dụng các logic nghiệp vụ đó.

Giải pháp: Ta có một lớp OverdueSpecification được được thỏa mãn khi ngày đến hạn của hóa đơn là 30 ngày trở lên, một lớp NoticeSentSpecification được thỏa mãn khi thông báo đã được gửi cho khách hàng và một lớp InCollectionSpecification được thỏa mãn khi hóa đơn đã được gửi đến cơ quan thu nợ. Sử dụng ba lớp specification này, ta tạo ra một lớp specification mới có tên SendToCollection, sẽ được thỏa mãn khi hóa đơn quá hạn, khi thông báo đã được gửi cho khách hàng và chưa được gửi đến cơ quan thu nợ.

2. Triển khai Specification Pattern trong Laravel

Khi truy vấn cơ sở dữ liệu, ta rất hay phải kết hợp các điều kiện truy vấn khác nhau (where, orWhere, whereIn…). Ví dụ lấy ra các jobs có company_id tương ứng, lấy ra 1 model có id tương ứng, orderBy theo cột, eager loading relationships… Mỗi điều kiện ta sẽ tạo ra một class Specification tương ứng (như CompanyIdSpecification, IdSpecification, OrderBySpecification, WithRelationsSpecification), có thể tái sử dụng ở nhiều nơi trong code.

Interface SpecificationInterface

Class AndSpecification để xâu chuỗi các Specification theo logic và

Class OrSpecification để xâu chuỗi các Specification theo logic hoặc

Class NoneSpecification

Class CompanyIdSpecification

Class IdSpecification

Class OrderBySpecification

Class WithRelationsSpecification

Sử dụng specification trong lớp controller, service hoặc repository: Ví dụ lấy ra các jobs có company_id = 15, eager loading các ứng viên của mỗi job và sắp xếp các jobs theo thời gian tạo

3. Tài liệu tham khảo

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo