Giải pháp chuyển đổi số trọn gói cho doanh nghiệp Việt
Bài học hôm nay chúng ta cùng xem qua cách tổ chức các phương thức getter và setter trong Java. Hai phương thức này là gì? Chúng có liên hệ như thế nào đến việc gói ghém dữ liệu? Và gói ghém dữ liệu là gì? Mời các bạn cùng đọc tiếp nhé.
Getter và setter là hai tên gọi của hai thể loại phương thức. Chúng có liên quan đến đặc tính gói ghém dữ liệu trong lập trình hướng đối tượng, tiếng Anh gọi đặc tính này là encapsulation. Trước đó, các định nghĩa về khả năng truy cập cũng là một dạng của gói ghém dữ liệu.
Chúng ta làm quen với gói ghém dữ liệu. Tính gói ghém dữ liệu là một trong những đặc tính cơ bản trong kế thừa, bên cạnh các đặc tính khác, như tính kế thừa (inheritance) mà bạn đã biết, tính đa hình (polymorphism) và tính trừu tượng (abstraction) mà bạn sẽ làm quen sau. Đặc tính gói ghém dữ liệu giúp che đi các thuộc tính của một lớp, khiến cho các lớp khác không thể “nhìn thấy”, không thể thay đổi hay chỉnh sửa các giá trị của các thuộc tính này. Bạn cũng được biết các khả năng truy cập private hay protected đều giúp ích rất nhiều trong việc gói ghém dữ liệu đúng không nào.
Vậy getter và setter liên quan gì đến gói ghém dữ liệu? Các phương thức này giúp việc quản lý các thuộc tính private hay protected của một lớp được thoải mái và tường minh hơn. Bạn có thể chỉ định các thuộc tính này sao cho chỉ được phép đọc (thông qua phương thức getter), hoặc chỉ được phép ghi (thông qua phương thức setter), hoặc cho phép cả đọc lẫn ghi (thông qua cả getter và setter) từ các lớp bên ngoài.
Định nghĩa trên chắc đủ rõ ràng cho bạn để hiểu loại phương thức này đúng không. Nếu chưa thực sự hiểu về nó thì mời bạn đọc tiếp các phần sau nhé.
Để getter và setter được tạo ra nhưng vẫn đảm bảo sự gói ghém cho các thuộc tính trong một lớp, chúng ta có các nguyên tắc sau.
– Luôn có thói quen định nghĩa khả năng truy cập cho các thuộc tính trong một lớp là private.
– Sau đó tùy nhu cầu mà xây dựng phương thức getter hay setter, hay cả getter và setter cho từng thuộc tính private đó. Với các phương thức setter bạn nên đặt tên theo cấu trúc setTênThuộcTính(). Còn với getter thì bạn nên đặt là getTênThuộcTính(). Việc xuất hiện của getter và setter cho các thuộc tính private là không bắt buộc. Bạn có thể không cần khai báo bất cứ getter hay setter nào cả nếu như bạn không muốn thuộc tính đó được thấy bởi bất kỳ lớp nào. Hoặc bạn chỉ cần xây dựng getter cho một thuộc tính private nếu bạn muốn thuộc tính đó chỉ được xem, không được sửa chữa. Hoặc chỉ xây dựng setter cho một thuộc tính private nếu bạn muốn thuộc tính đó chỉ có khả năng chỉnh sửa từ bên ngoài mà không được xem. Hoặc có cả getter và setter nếu nó được phép xem và sửa.
Trường hợp thuộc tính private có cả getter lẫn setter thoạt nghe đến bạn có thể nghĩ rằng, tại sao không xây dựng public cho các thuộc tính này, tại sao lại phải rườm rà set nó là private, sau đó lại thêm cả getter lẫn setter?
Bạn nên biết, sự rườm rà này rất đáng giá, bạn nên tập làm quen với nguyên tắc gói ghém dữ liệu kiểu này. Đầu tiên nó tạo cho bạn một thói quen làm việc theo nguyên tắc, OOP là một lĩnh vực có khá nhiều nguyên tắc và đây là nguyên tắc đầu tiên mà bạn có thể dễ dàng để thực hiện. Sau đó, cách xây dựng getter và setter như thế này giúp giảm thiểu lỗi cho ứng dụng, ai mà biết với việc khai báo các thuộc tính của lớp là public ngay từ đầu, các lớp khác đều có quyền thấy và sửa chữa các thuộc tính này có gây ra bất kỳ lỗi tiềm ẩn nào hay không. Bạn tưởng tượng xem khi đối tượng HinhTron được khởi tạo với một banKinh được chỉ định ở constructor, nhưng khi bắt đầu vào tính diện tích thì ở đâu đó lại truy xuất đến thuộc tính banKinh public và chỉnh sửa nó, phương thức tính diện tích lúc này có thể sẽ cho ra kết quả không mong muốn. Nhưng với getter và setter được khai báo, bạn có quyền thêm các dòng code đảm bảo tính đúng đắn của dữ liệu truyền vào cho thuộc tính banKinh (bài thực hành số 2 dưới đây giúp bạn rõ hơn), hơn nữa bạn còn có thể kiểm tra các điều kiện xem thuộc tính này có đang được dùng để tính toán ở đâu không, có cần phải thay đổi ngay lúc này hay delay bao lâu để tránh việc sai số cho các tính toán hay không.
Nào, để dễ hiểu một chút, chúng ta cùng đến với bài thực hành sau. Chúng ta hãy xây dựng lại lớp HinhHoc theo đúng tiêu chí của gói ghém dữ liệu bằng cách chỉ định các thuộc tính ở lớp này là private.
Bạn có thể thấy, lớp HinhTron đã gói ghém các thuộc tính của nó, sao cho banKinh, chuVi và dienTich đều là private. banKinh chỉ được khởi tạo duy nhất khi HinhTron được khởi tạo. Sau đó, việc tinhChuVi() hay tinhDienTich() diễn ra an toàn, banKinh không thể được thay đổi ở bất kỳ một chỗ nào đó khác trong toàn bộ chương trình. Các lớp khác bên ngoài cũng không thể nào tự thay đổi các thuộc tính chuVi và dienTich, nó thuộc quyền quản lý và tùy ý thay đổi của riêng HinhTron mà thôi. Bạn hãy xem main() sử dụng HinhTron như sau.
Nếu giờ đây bạn muốn main() in ra kết quả của các phép tính chu vi và diện tích, hãy thêm getter cho các thuộc tính này bên trong HinhTron.
Khi đó main() có thể đọc được các giá trị bên trong HinhTron như thế này.
Bạn đã hiểu cách dùng getter và setter rồi đúng không nào. Bài thực hành tiếp theo đây cho chúng ta thấy thêm một lợi ích và cách sử dụng nữa của việc sử dụng chúng.
Bài thực hành này xây dựng lớp SinhVien với các thuộc tính private kèm với các phương thức getter và setter cho chúng. Bạn có thể thấy rằng bạn hoàn toàn có thể tùy biến sao cho chính setter là một phương thức private (bạn không cho ghi vào thuộc tính từ bên ngoài lớp luôn, nhưng chính setter private này lại giúp kiểm tra chút ràng buộc điều kiện). Phương thức getter getTuoi() cũng được xử lý một chút trước khi trả kết quả ra bên ngoài.
Với khai báo lớp như trên. Giả sử mình khởi tạo các đối tượng sinh viên này ở main() như sau.
Sau đây là kết quả in ra console.
Như trên mình có nói, việc đặt tên cho getter và setter nên là getTênThuộcTính() và setTênThuộcTính(). Tuy nhiên, InteliJ đã hỗ trợ chúng ta một công cụ tự động phát sinh tên cho các phương thức getter và setter của thuộc tính private nào đó .
Bạn hãy cùng mình thử nghiệm tính năng sinh code tự động qua các bước sau. Đầu tiên bạn hãy thử tạo một lớp ToaDo có khai báo một hay nhiều thuộc tính private như sau.
https://i0.wp.com/yellowcodebooks.com/wp-content/uploads/2022/12/Screenshot-2022-12-20-at-11.23-1.png?resize=300%2C202&ssl=1 300w" data-lazy-loaded="1" sizes="(max-width: 636px) 100vw, 636px" loading="eager" style="box-sizing: border-box; height: auto; max-width: 100%; border-style: none; margin: 0px; vertical-align: bottom;">Nếu bạn click lên một trong các thuộc tính private này, bạn sẽ thấy icon cảnh báo màu vàng bên thanh trái của editor. Vì hệ thống thấy rằng chúng ta khai báo private cho thuộc tính, mà không sử dụng chúng ở bên trong lớp, thì hiển nhiên là có vấn đề rồi, vì bên ngoài lớp có nhìn thấy các giá trị này đâu.
Khi này bạn cứ click vào một trong các cảnh báo này, một dialog nhỏ xuất hiện như sau.

Bạn đã thấy có các tùy chọn Create getter for ‘x’ và Create setter for ‘x’. Vâng, đó là các cách mà InteliJ sẽ thêm tự động các phương thức getter và setter. Bạn có thể tự trải nghiệm nhé, mình toàn dùng chúng cho việc tạo nhanh code đấy.
Vậy là chúng ta vừa xem qua kiến thức về xây dựng các phương thức getter và setter trong hướng đối tượng. Thực ra, việc có nên xây dựng getter và setter cho các thuộc tính của lớp trong Java hay cứ khai báo public hết cho chúng, từng là chủ đề tranh cãi. Vì nhìn chung lại getter và setter sẽ làm cho các lớp trở nên rườm rà hơn. Có một số ý kiến cũng cho rằng hiệu năng của ứng dụng cũng giảm đi với getter và setter. Nhưng như bài học có nói đến, rằng đây là một trong những cách gói ghém dữ liệu của lớp. Với getter và setter, bạn sẽ có thể chỉ định được thuộc tính đó hoàn toàn ẩn, hay chỉ đọc, hay chỉ ghi, hay có thể đọc và ghi. Một cách để làm cho code bạn được tường minh hơn, ít lỗi hơn, và tuân thủ nguyên tắc OOP hơn.
Chưa có câu hỏi nào cho bài này.