Sử dụng Intelligent constants trong lập trình Android

540

Bài viết được sự cho phép của tác giả Sơn Dương

Constants được sử dụng ở khắp mọi nơi trong hầu hết các dự án. Với dự án Android cũng vậy, chúng được sử dụng rất nhiều.

Bạn có bao giờ tự hỏi liệu có thể làm cho Constants trở nên thông minh hơn chưa? Nghe có vẻ phi lý nhưng lại rất hợp lý

Bài viết này mình sẽ hướng dẫn các bạn tạo Intelligent constants trong dự án Android nhé!

#Thực hành tạo Intelligent Constants

Chúng ta cùng xem xét một kịch bản là bạn muốn truyền một flag vào một hàm và thực hiện một việc gì đó dựa trên giá trị được truyền vào.

Ví dụ: Mình có một hàm có 3 tham số. Tham số thứ nhất và thứ 2 là kiểu số (Integer), còn tham số thứ 3 là một Operation để thực hiện 2 tham số kia.

Đại khái như sau:

private int performOperation(int a, int b, <operation>)

Bạn sẽ chọn kiểu dữ liệu nào cho tham số <operation> ?

Dưới đây là một số phương án:

1. Enums

Giải pháp đầu tiên mà bạn nghĩ đến là kiểu Enum. Enum là kiểu dữ liệu rất đặc biệt với nhiều tính năng được Java cung cấp sẵn.

public enum Operations {
    ADD, SUBTRACT, DIVIDE, MULTIPLY
}

private int performOperation(int a, int b, Operations operation) { }

someFunction() {
  performOperation(1, 2, Operations.ADD);
}

Mặc dù Enums dễ đọc, dễ sử dụng và có thể gọi từ bất kì nơi nào nhưng chúng lại khá nặng, đặc biệt đối Android với nguồn tài nguyên hạn chế.

Enums trong Java có nhiều đặc điểm nổi bật như:

  • Tính đóng gói (packed).
  • Gần giống với Class, khi bạn có thể có các methods bên trong (cả concrete và abstract methods).
  • Dễ dàng chuyển từ String sang Enum Object.

Trong trường hợp ví dụ của mình thì Enum được sử dụng như một hằng số.

  Android Adaptive Launcher Icon – Tất Cả Thông Tin Bạn Cần Biết

  5 lỗi phổ biến thường gặp khi lập trình Android

2. Simple Constants

Thay vì sử dụng Enum, chúng ta có thể sử dụng số nguyên làm hằng số theo cách truyền thống mà mọi người hay làm, đại khái như bên dưới:

public static final int ADD = 0;
public static final int SUBTRACT = 1;
public static final int DIVIDE = 2;
public static final int MULTIPLY = 3;

private int performOperation(int a, int b, int operation) { }

Với cách định nghĩa Constant kiểu này, code sẽ nhẹ hơn so với sử dụng Enum nhưng có nhược điểm là khi sử dụng chúng ta không biết truyển Constant nào cho chính xác.

Thậm chí nguy hiểm hơn nữa là có thể truyền một số nguyên không được định nghĩa hằng số trước, dẫn đến ứng dụng chạy sai logic hoặc thậm chí bị crash.

3. Intelligent Constants

Intelligent constants tận dụng được ưu điểm của cả Enum và simple constant bằng cách sử dụng annotation.

Android cung cấp 2 annotation:@IntDef và @StringDef để giúp chúng ta làm điều đó. Hai annotation này mang lại điều gì? Câu trả lời là chúng sẽ làm cho Constants trở nên “thông minh” hơn!

Nghe có vẻ điêu điêu đúng không! Nhưng hãy khoan hoài nghi mà hãy tham khảo code bên dưới:

// Constants
public static final int ADD = 0;
public static final int SUBTRACT = 1;
public static final int DIVIDE = 2;
public static final int MULTIPLY = 3;

// Bundling them under one definition
@Retention(RetentionPolicy.SOURCE)
@IntDef({ADD, SUBTRACT, DIVIDE, MULTIPLY})
public @interface OperationsDef { }

private int performOperation(int a, int b, @OperationsDef int operation) { }

Ở đây chúng ta tạo annotate definition cho Constant OperationsDef. Sau đó annotate này cho tham số thứ 3 trong hàm mà mình ví dụ ở trên. Điều kì diệu bắt đầu từ đây!

Việc gọi hàm để sử dụng giờ đã trở nên dễ dàng hơn. Không những vậy, trình biên dịch sẽ báo lỗi nếu như dev cố tình truyền một hằng số nằm ngoài những giá trị mà chúng ta đã định nghĩa trước. Điều này sẽ hạn chế rất nhiều những lỗi Runtime. Quá tuyệt phải không?

Intelligent constants

Có rất nhiều annotations kiểu này mà chúng ta vẫn hay sử dụng trong ứng dụng Android, chỉ có điều chúng ta không để ý đó thôi.

Ví dụ như View.VISIBLEView.GONEView.INVISIBLE… Chúng đều là những @IntDef.

public static final int VISIBLE = 0x00000000;
public static final int INVISIBLE = 0x00000004;
public static final int GONE = 0x00000008;

@IntDef({VISIBLE, INVISIBLE, GONE})
@Retention(RetentionPolicy.SOURCE)
public @interface Visibility { }

Bài viết này nhằm cung cấp cho bạn một cách thức khác khi làm việc với Constant. Hi vọng rằng các bạn sẽ thích và nhớ để lại comment ủng hộ mình nhé!

Bài viết gốc được đăng tải tại vntalking.com

Tìm việc làm IT mọi cấp độ tại TopDev