Flutter Clean Architecture (Part 4) – Tổng quan Data Layer & Model

Trần Đình Quý

Updated on:

Flutter Clean Architecture

Mặc dù domain layer là trung tâm an toàn của app, độc lập với các lớp khác, nhưng data layer lại là nơi ứng dụng làm việc với thế giới bên ngoài khắc nghiệt của API và thư viện bên thứ 3. Nó bao gồm Data resource, Repository là nguồn sự thật duy nhất cho dữ liệu và cuối cùng là Model.

Tiếp tục đi ra ngoài

Bạn có thể để ý rằng chúng ta luôn bắt đầu làm việc từ các phần bên trong của app trước và là tiến dần ra phía ngoài. Chúng ta đã bắt đầu với phần hoàn toàn độc lập trước, đó là Domain và thậm chí chúng ta đã tạo ra Entity đầu tiền. Bây giờ, chúng ta sẽ bắt đầu với Model và chỉ sau đó mới tiếp tực triển khai Repository và Data Resource.

Toàn bộ clean architecture được xác đinh dựa trên một nguyên tắc cơ bản – các lớp bên ngoài phụ thuộc vào các lớp bên trong và được biểu thị bằng các mũi tên ở hình dưới.

Dependencies flow inward

Do đó, sẽ hợp lý nếu bắt đầu ở trung tâm, vì nếu không, chúng ta sẽ gặp khó khăn khi triển khai các Use case, chẳng hạn như nếu chúng ta không có bất kỳ Entity nào có thể được trả về trước.

Tất cả những điều này chỉ có thể thực hiện được thông qua sức mạnh của contract, trong trường hợp của Dart được triển khai dưới dạng các abstract class.

Tổng quan Data Layer

Chúng ta biết rằng interface công khai của Repository sẽ trông như thế nào. Nó được định nghĩa bởi contract dưới đây từ Domain Layer.

number_trivia_repository.dart

abstract class NumberTriviaRepository {
  Future<Either<Failure, NumberTrivia>> getConcreteNumberTrivia(int number);
  Future<Either<Failure, NumberTrivia>> getRandomNumberTrivia();
}

Tất nhiên dữ liên không thể được lấy ra đâu đó ất ơ được. Vì vậy trước khi triển khai Repository chúng ta phải tạo Remote và Local Data Resource.

Nhưng mà hãy xem lại xem cách mà Data Layer tương tác để lấy dữ liệu.

Data layer operates with Models

Vậy thì chúng ta phải có Model trước.

Sự cần thiết của Models

Các kiểu trả về phương thức của các nguồn dữ liệu sẽ rất giống với các kiểu trong Repository nhưng có hai điểm khác biệt lớn. Họ sẽ không trả về các lỗi bên trong bằng cách sử dụng Failure, thay vào đó họ sẽ đưa ra các Exception. Ngoài ra, thay vì trả về các thực thể NumberTrivia, chúng sẽ trả về các đối tượng NumberTriviaModel.

Tất cả điều này xảy ra bởi vì các nguồn dữ liệu nằm ở ranh giới tuyệt đối giữa thế giới tốt đẹp và ấm cúng của code của chúng ta và thế giới bên ngoài đáng sợ của API và thư viện bên thứ 3.

Mô hình là các thực thể có thêm một số chức năng bổ sung ở trên cùng. Trong trường hợp của chúng ta, đó sẽ là khả năng được serialize và deserialize đến/từ JSON. API sẽ phản hồi bằng dữ liệu ở định dạng JSON, vì vậy chúng ta cần có cách chuyển đổi nó thành Dart object.

Cài đặt Model 

File dành cho Model sẽ nằm trong thư mục models cho tính năng number_trivia.

Trước tiên chúng ta sẽ tạo ra 1 Trivia Model đơn giản.

number_trivia_model.dart

import '../../domain/entities/number_trivia.dart';

class NumberTriviaModel extends NumberTrivia {
  const NumberTriviaModel({
    required super.text,
    required super.number,
  });
}

From JSON

Logic chuyển đổi đầu tiên mà chúng ta sẽ triển khai sẽ là phương thức fromJson sẽ trả về một phiên bản NumberTriviaModel có cùng dữ liệu như có trong chuỗi JSON.

import '../../domain/entities/number_trivia.dart';

class NumberTriviaModel extends NumberTrivia {
...
  factory NumberTriviaModel.fromJson(Map<String, dynamic> json) {
    return NumberTriviaModel(
      text: json['text'],
      // The 'num' type can be both a 'double' and an 'int'
      number: (json['number'] as num).toInt(),
    );
  }
}

To JSON

Bây giờ chúng ta hãy chuyển sang phương thức chuyển đổi thứ hai – toJson. Theo quy ước, đây là một phương thức trả về Map<String, Dynamic>.

import '../../domain/entities/number_trivia.dart';

class NumberTriviaModel extends NumberTrivia {
...
  Map<String, dynamic> toJson() {
    return {
      'text': text,
      'number': number,
    };
  }
}

Tiếp theo

Bây giờ chúng ta đã có Model có thể được chuyển đổi thành/từ JSON. Phần tiếp theo chúng ta sẽ bắt đầu thực hiện các contract Data Source và triển khai Repository.

Phần trước: https://dev.tora-tech.com/flutter-ca-tai-cau-truc-domain-layer/

Phần tiếp theo: https://dev.tora-tech.com/flutter-ca-contracts-trong-data-sources/

Viết một bình luận