Mẫu thiết kế kho lưu trữ trong Swift

Một cách rõ ràng để truy vấn mô hình của bạn

vấn đề gì nó giải quyết?

Nếu bạn cần truy vấn các đối tượng mô hình của mình từ các vị trí khác nhau trong mã của mình nhiều lần, một kho lưu trữ có thể thực sự hữu ích để cung cấp một điểm nhập duy nhất để làm việc với các mô hình của bạn và xóa mã truy vấn trùng lặp. Bạn có thể đưa nó đi xa hơn và sử dụng nó với các giao thức, bằng cách này bạn có thể dễ dàng chuyển đổi các triển khai (ví dụ cho các bài kiểm tra đơn vị) hoặc bạn có thể sử dụng nó với các tổng quát để tạo ra một bản tóm tắt chung * trống cuộn *. Trong bài viết này tôi sẽ đề cập đến tất cả các trường hợp này.

Phác thảo hiện trường.

Hãy nói rằng bạn có một số mã tìm nạp dữ liệu từ API và ánh xạ mã này đến các đối tượng mô hình. Trong ví dụ này, tôi sẽ tìm nạp danh sách các bài báo từ máy chủ.

Điều này có vẻ hơi thú vị, nhưng nó chỉ là RxSwift, sử dụng Moya làm lớp trừu tượng mạng, nhưng điều đó thực sự quan trọng để hiểu những gì xảy ra. Cách bạn lấy dữ liệu của bạn hoàn toàn phụ thuộc vào bạn.

Đoạn mã này

  1. Yêu cầu NHẬN đến máy chủ
  2. Ánh xạ JSON được trả về vào một mảng các đối tượng Article
  3. Việc đóng cửa được gọi khi tất cả các công việc được thực hiện.

Tại sao chúng ta cần một kho lưu trữ?

Vâng, tại thời điểm này, chúng tôi không có gì. Nếu bạn chỉ gọi API một lần trong toàn bộ cơ sở mã của mình, việc thêm kho lưu trữ có thể là quá mức cần thiết (hoặc như một số người có thể nói là quá kỹ thuật).

Ok, nhưng khi nào thì một đối tượng kho lưu trữ thuận tiện để sử dụng?
Hãy để nói rằng cơ sở mã của bạn bắt đầu phát triển và bạn cần viết mã để tìm nạp các bài báo nhiều lần. Bạn có thể nói, hãy để cho phép sao chép mã và dán mã vào bất cứ nơi nào bạn cần để tìm nạp tất cả các bài viết.

Không có hại gì, không ai chết. Đúng?

Tại thời điểm đó, một báo động lớn màu đỏ sẽ bắt đầu nhấp nháy trong não của bạn.

Xin chào kho lưu trữ.

Kho lưu trữ chỉ là một đối tượng đóng gói tất cả mã để truy vấn các mô hình của bạn ở một nơi, do đó bạn có một điểm nhập duy nhất nếu bạn muốn, ví dụ: nhận được tất cả các bài viết.

Hãy để chúng tôi tạo một đối tượng lưu trữ cung cấp API công khai để lấy các bài viết.

Bây giờ chúng tôi có thể gọi phương thức này và chúng tôi không phải lo lắng về những gì xảy ra đằng sau hậu trường để có được những bài báo thực tế.
Chỉ cần gọi phương thức, và bạn nhận được các bài viết. Tốt đẹp?
Nhưng chờ đợi, có nhiều hơn nữa!

Xử lý tất cả các tương tác bài viết

Chúng ta có thể sử dụng kho lưu trữ để thêm nhiều phương thức để tương tác với đối tượng mô hình của mình. Hầu hết các lần bạn muốn thực hiện các thao tác CRUD (tạo, đọc, cập nhật, xóa) trên mô hình của bạn. Vâng, chỉ cần thêm logic cho các hoạt động này trong kho lưu trữ.

Điều này tạo ra một API đẹp để sử dụng trong toàn bộ mã của bạn, mà không phải lặp đi lặp lại cùng một mã.

Trong thực tế, việc sử dụng một kho lưu trữ sẽ như thế này.

Khá đẹp và dễ đọc, phải không? Nhưng chờ đã, nó thậm chí còn trở nên tốt hơn.

Bật nguồn: giao thức

Trong đoạn mã trước, tôi luôn sử dụng ví dụ về ‘lấy dữ liệu từ API API. Nhưng nếu bạn cần thêm hỗ trợ để tải dữ liệu từ tệp JSON cục bộ thay vì nguồn trực tuyến.

Chà, nếu bạn tạo một giao thức liệt kê các tên phương thức, bạn có thể tạo một triển khai cho API trực tuyến và một giao thức để lấy dữ liệu ngoại tuyến.

Điều này có thể trông như thế này.

Một giao thức chỉ nói nếu bạn tuân thủ tôi, bạn cần phải có các chữ ký phương thức này, nhưng tôi không quan tâm đến việc triển khai thực tế!

Vì vậy, rất hay, bạn có thể tạo một WebArticleRep repository và LocalArticleRep repository. Cả hai đều có tất cả các phương thức được liệt kê trong giao thức, nhưng bạn có thể viết 2 cách thực hiện hoàn toàn khác nhau.

Bật nguồn: Kiểm tra đơn vị

Việc sử dụng các giao thức cũng thực sự thuận tiện khi bạn muốn đơn vị kiểm tra mã của mình, bởi vì bạn chỉ có thể tạo một đối tượng khác thực hiện giao thức kho lưu trữ, nhưng thay vào đó trả về dữ liệu giả.

Nếu bạn sử dụng điều này cùng với tiêm phụ thuộc, nó thực sự dễ dàng để kiểm tra một đối tượng cụ thể.

Một ví dụ

Hãy để nói rằng bạn có một mô hình xem và mô hình xem lấy dữ liệu của nó thông qua một kho lưu trữ.

Nếu bạn muốn kiểm tra mô hình xem, bạn có thể bị mắc kẹt với các bài viết sẽ được tìm nạp từ web.
Đây thực sự không phải là những gì chúng ta muốn. Chúng tôi muốn thử nghiệm của chúng tôi có tính quyết định càng nhiều càng tốt. Trong trường hợp này, các bài viết được truy xuất từ ​​web có thể thay đổi theo thời gian, không thể có kết nối internet tại thời điểm kiểm tra chạy, máy chủ có thể ngừng hoạt động, Đây là tất cả các tình huống có thể xảy ra trong đó các thử nghiệm của chúng tôi sẽ thất bại, vì chúng là ngoài tầm kiểm soát của chúng tôi Và khi chúng tôi kiểm tra, chúng tôi muốn / cần phải kiểm soát.

May mắn thay, nó thực sự đơn giản để giải quyết điều này.

Xin chào, tiêm phụ thuộc.

Bạn chỉ cần đặt thuộc tính articleRepo thông qua trình khởi tạo. Trường hợp mặc định, sẽ là trường hợp bạn muốn cho mã sản xuất của mình và khi bạn viết một bài kiểm tra đơn vị, bạn có thể trao đổi kho lưu trữ với phiên bản giả của mình.

Nhưng có lẽ bạn đang nghĩ, vậy còn các loại thì sao? WebArticleRep repository không phải là MockArticleRep repository, vì vậy trình biên dịch sẽ không phàn nàn? Vâng, không phải nếu bạn sử dụng giao thức như một loại. Bằng cách này, chúng tôi cho trình biên dịch biết, cho phép mọi thứ miễn là nó phù hợp với giao thức ArticleRep repository (điều mà cả Web và MockArticleRep repository đều làm).

Mã cuối cùng sẽ trông như thế này.

Và trong bài kiểm tra đơn vị của bạn, bạn có thể trao đổi nó như thế này.

Bây giờ bạn có toàn quyền kiểm soát dữ liệu mà kho lưu trữ của bạn trả về.

Siêu năng lực: thuốc generic

Bạn có thể thực hiện điều này hơn nữa, bằng cách sử dụng thuốc generic. Nếu bạn nghĩ về nó, hầu hết các kho lưu trữ luôn có cùng các hoạt động

  1. có được tất cả mọi thứ
  2. lấy một số thứ
  3. chèn một số thứ
  4. xóa điều
  5. cập nhật một điều

Chà, điều duy nhất khác biệt là từ ‘điều, vì vậy đây có thể là một ứng cử viên xuất sắc để sử dụng một giao thức với tướng. Nghe có vẻ phức tạp, nhưng thực ra nó rất đơn giản để làm.

Đầu tiên, chúng tôi sẽ đổi tên giao thức thành Kho lưu trữ, để làm cho nó trở nên chung chung hơn.
Và sau đó, chúng tôi sẽ loại bỏ tất cả các loại bài viết và thay thế chúng bằng phép thuật T. Nhưng chữ T chỉ là sự thay thế cho những thứ mà chúng tôi muốn. Chúng ta chỉ cần đánh dấu T là loại giao thức liên quan.

Vì vậy, bây giờ chúng ta có thể sử dụng giao thức này cho bất kỳ đối tượng mô hình nào chúng ta có.

1. Kho lưu trữ bài viết

Trình biên dịch sẽ suy ra loại T thành Điều, bởi vì bằng cách thực hiện các phương thức, chúng tôi đã chỉ định T là gì. Trong trường hợp này một đối tượng Điều.

2. Kho lưu trữ người dùng

Đó là nó.

Tôi hy vọng bạn thích bài viết này và nếu bạn có bất kỳ câu hỏi hoặc nhận xét nào, chỉ cần hỏi họ bên dưới hoặc liên hệ với tôi trên Twitter và để cho Lát có một cuộc trò chuyện.