Thứ Bảy, 9 tháng 4, 2016

Khám phá 6 vai trò của interface trong thế giới Java - Phần cuối

Bài gốc tại Java World.

Dành cho những ai mới học Java. Phần kế tiếp đưa thêm những thông tin rất thú vị về interface. 

Tác giả: Jeff Friesen
Dịch giả: Minh Hiếu
Hiệu chỉnh: Lộc Hồ
Đính chính: Nhữ Đình Thuận



Vai trò 3: Tạo thuận lợi cho sự phát triển thư viện
Java 8 giới thiệu tính năng đặc biệt hữu dụng là Lamda và Streams API đặt trọng tâm vào đối tượng cần được áp dụng xử lý hơn là phương thức xử lý chúng. Lambdas và Streams tạo sự thuận tiện cho nhà phát triển triển khai xử lý song song (parallelism) trong ứng dụng của họ. Một điều không may, việc nâng cấp những tính năng này cho Java Collection Framework đòi hỏi phải viết lại code một cách mở rộng hơn.

Để nhanh chóng cải tiến collection cho việc sử dụng stream nguồn và đích, Java đưa vào khái niệm cài đặt mặc định hàm (default method) cho interface, chúng là non-static method với phần đầu method có thêm từ khoá default và mã lệnh xử lý ở phần thân - đây là điểm rất mới của Java.  Như vậy interface có code cài đặt mặc định, chúng có thể không cần được viết lại (hoặc có - overriden - ghi đè) bởi class cài đặt interface đó. Code cài đặt mặc định method của interface có thể được triệu gọi thông qua objects references  - tham chiếu tới đối tượng.

Method mặc định trở thành một phần của ngôn ngữ, theo đó chúng được thêm vào java.util.Collection interface cung cấp cầu nối giữa collections và streams:  

default Stream parallelStream(): Trả về một parallel java.util.stream.Stream object từ collection nguồn.
default Stream stream(): Trả về một Stream object tuần tự từ collection nguồn.

Giả sử bạn khai báo biến thuộc lớp java.util.List với giá trị được gán như sau:

List innerPlanets = Arrays.asList("Mercury", "Venus", "Earth", "Mars");

Cách viết thông thường - vòng lặp cho collection như dưới đây để in ra tên các thành viên trong innerPlanets:

for (String innerPlanet: innerPlanets) {
   System.out.println(innerPlanet);
}

Với Java 8, bạn có thể thay thế bằng một external iteration, tập trung vào cách thực thi nghiệp vụ dựa trên Stream internal iteration, nó tập trung vào việc nghiệp vụ sẽ xử lý ra sao, ví dụ:


innerPlanets.stream().forEach(System.out::println);

hoặc

innerPlanets.parallelStream().forEach(System.out::println);

Ở đây, innerPlanets.stream() và innerPlanets.parallelStream() trả về đối tượng Stream tuần tự và song song từ List nguồn trước đó. Hàm forEach triệu gọi trên tham chiếu của Stream trả về, sẽ duyệt (lặp) các phần tử (element) và gọi hàm System.out.println() để in ra chúng. 

Phương thức mặc định có thể  khiến code trở nên dễ đọc hơn. Ví dụ, lớp java.util.Collections cài đặt một static method: 

static void sort(List list, Comparator c)

 cho việc sắp xếp thứ tự các phần tử của list thông qua một comparator chỉ định. Tuy nhiên,  Java 8 đã thêm vào default method
  void sort(Comparator c) 
  
  cho List interface, do đó chúng ta cũng có thể sắp xếp trực tiếp trên đối tượng của List bằng cách gọi như  myList.sort(comparator) thay vì phải sử dụng phương thức của Collections util class. 

Hàm mặc định (default method) đã tạo ra kỷ nguyên mới cho Java Collections Framework. Bạn có thể xem vai trò này được tạo ra từ di sản của các thư viện thiết kế trên interface. 

Ghi chú từ Nhữ Đình Thuận: Như vậy, thiết kế một thư viện/framework hay đơn thuần một mã lệnh dựa trên trừu tượng, interface, design đã được tăng cường sức mạnh thông qua default method. Tác giả bài viết ở phần này muốn nêu bật vai trò cài đặt mặc định của hàm trên interface là cầu nối giữa collection và stream, biến cách duyệt tập thành cách duyệt giống như luồng. Ngoài ra, default method cũng tạo giao diện sáng sửa hơn cho collection bằng cách gọi trực tiếp trên object thay vì phải dùng đến util class - lớp tiện ích/phụ trợ.

Vai trò 4: Phục vụ như kho constant

Phiên bản Java 5 trước đó đã đưa ra static imports vào ngôn ngữ và enums, interfaces được sử dụng rộng rãi hơn như một constant repositories (kho resources tĩnh gồm thuộc tính và hàm tĩnh). Nhờ đó, những lập trình viên lười biếng có thể sử dụng interface thay cho class trong việc  sử dụng enumerated type (kiểu dữ liệu liệt kê), tránh việc phải thêm tên lớp làm tiền tố khi sử dụng giá trị constant trong class cài đặt interface. Code dưới đây như một ví dụ minh hoạ constant trong interface. 

public interface Directions {
   int NORTH = 0;
   int SOUTH = 1;
   int EAST = 2;
   int WEST = 3;
}

public class Compass implements Directions {

   private int curDirection;

   // ... other code

   public void printDirection()    {
      switch (curDirection)  {
         case NORTH: System.out.println("North"); break;
         case SOUTH: System.out.println("South"); break;
         case EAST : System.out.println("East"); break;
         case WEST : System.out.println("West"); break;
         default   : System.out.println("Unknown");
      }
   }
}

Constant interface có thể là nguyên nhân đau đầu khi maintenance - bảo trì. Để đảm bảo tương thích nhị phân, class phải luôn cài đặt interface, ngay cả khi class không cần đến những giá trị constants. Giá trị constant có thể gây bối rối cho người sử dụng class - có lẽ chúng không cần gọi từ bên ngoài class nhưng chúng vẫn được nhìn thấy bởi vì biến trong interface thực chất là các biến được khai báo dạng public + static + final. 

Khắc phục vấn đề này, chúng ta chuyển interface sang class, khai báo các biến constant là public + static + final

public class Directions {
      public final static int NORTH = 0;
      public final static int SOUTH = 1;
      public final static int EAST = 2;
      public final static int WEST = 3;
}


và sử dụng static import như dưới đây :

import static Directions.*;

khi đó, gọi đến các biến constant trong lớp Compass không cần phải thêm tiền tố Directions vào nữa. 

Trường hợp này, enum là một lựa chọn tốt hơn

public enum Directions { NORTH, SOUTH, EAST, WEST }

và mã lệnh lớp Compass 

public class Compass {
   private Directions curDirection;

   // ... other code

   public void printDirection()s {
      switch (curDirection)  {
         case NORTH: System.out.println("North"); break;
         case SOUTH: System.out.println("South"); break;
         case EAST : System.out.println("East"); break;
         case WEST : System.out.println("West"); break;
         default   : System.out.println("Unknown");
      }
   }
}

Không nên và không bao giờ sử dụng constant interface.

Vai trò 5: Nơi chứa cho các phương thức tiện ích - utility methods

Cùng với phương thức mặc định, static method cũng là một điểm mới mà Java 8 tăng cường hỗ trợ cho interface. Khả năng mở ra tất cả những gì có thể như ví dụ dưới đây.

public interface Fillable {
   public void fill(int color);

   public static int rgb(int r, int g, int b) {
      return r << 16 | g << 8 | b;
   }
}

Fillable là interface có thể sử dụng cho graphical object - đối tượng đồ hoạ như hình tròn, hình vuông, nó có khả năng tự thân phủ màu bằng phương thức fill(). Để tiện hơn, rgb() - hàm tĩnh khai báo trong Fillable là một tiện ích giúp chuyển giá trị của mã màu red/green/blue tới số 32-bit value cho việc truyền vào khi gọi hàm fill(). Ví dụ:

int rgb = Fillable.rgb(200, 108, 29);

Vai trò 6: Nhận diện class với những tính năng đặc biệt

Vai trò cuối của interface là giúp nhận diện những tính năng đặc biệt của lớp cài đặt interface. Ví dụ, một class implement java.lang.Cloneable interface đồng nghĩa với việc phương thức Object.clone() có thể tạo ra bản sao của object với đầy đủ các thuộc tính có giá trị tương tự. Hoặc một class implements java.io.Serializable interface là dấu hiệu cho thấy các đối tượng của lớp đó có thể được phép serialized và deserialized - chuyển sang bytes hoặc ngược lại.

Cloneable and Serializable là empty interfaces - rỗng - không khai báo bất cứ hàm nào. Chúng tồn tại với mục đích duy nhất để xác định đối tượng tạo ra từ lớp cài đặt có thể clone (tạo bản sao) hay chuyển đổi thành bytes (serialized).

Kết luận

Người mới học java thường bối rối với interface bởi rất nhiều vai trò mà nó đảm nhận. Mặc dù tôi nghĩ mình đã đề cập đến tất cả các vai trò của nó nhưng cũng rất hân hạnh được các bạn quan tâm góp ý nếu còn thấy những vai trò khác của interface mà tôi chưa liệt kê.



Không có nhận xét nào:

Đăng nhận xét

nhudinhthuan@gmail.com