- vừa được xem lúc

[JavaScript] Bài 27 - Encapsulation in OOP

0 0 13

Người đăng: Semi Art

Theo Viblo Asia

Tiếp theo sau Inheritance, tính năng Đóng Gói Encapsulation luôn được quan tâm và hỗ trợ trước hết so với AbstractionPolymorphism. Để định nghĩa một cách ngắn gọn thì Encapsulation có thể được hiểu đơn giản là cho phép ẩn đi những yếu tố propertymethod mang tính chất cục bộ của một object. Điều này sẽ giúp đảm bảo code tương tác từ phía bên ngoài của object đó sẽ không thể trực tiếp sử dụng hay tạo ra sự thay đổi đối với các yếu tố cục bộ.

Đối với các ngôn ngữ OOP hoàn chỉnh như Java hay C#, tính năng Encapsulation được cung cấp bởi một bộ các từ khóa được gọi là Access Modifier - tạm hiểu là các nhãn quy định quyền truy cập tới các yếu tố của object. Các từ khóa được cung cấp trung Java bao gồm:

  • public - luôn khả dụng với code tham chiếu được viết ở bất kỳ đâu.
  • private - chỉ khả dụng với code tham chiếu được định nghĩa bên trong class đó; Code tham chiếu viết trong các class kế thừa cũng không thể truy xuất được các yếu tố private trong class cha.
  • default - khả dụng với code tham chiếu được định nghĩa trong cùng package.
  • protected - khả dụng với code tham chiếu được định nghĩa trong cùng package và các class kế thừa ở bên ngoài package đó.

Public & Private

Từ khóa public hiển nhiên không có gì đáng phải lưu ý, do đó chúng ta sẽ làm ví dụ ngay với private. Ở code ví dụ trong bài trước, chúng ta có thể sửa lại một chút và sử dụng các nhãn private cho các thuộc tính nameage. Lúc này ở chương trình main chúng ta sẽ thử truy xuất trực tiếp tới các thuộc tính này.

class Main { public static void main (String args[]) { Universe tabha = new Universe ("Tabha", 1001, "Buddhism"); System.out.println ("Name: " + tabha.name); System.out.println ("Age: " + tabha.age); } } //. Main // -- Entity - - - - - - - - - - - - - - - - - - - class Entity { private String name; private int age; Entity (String name, int age) { this.name = name; this.age = age; } void whisper () { System.out.println (this.age + " years ago..."); System.out.println (this.name + "..."); }
} //. Entity // -- Universe - - - - - - - - - - - - - - - - - - - class Universe extends Entity { String laws; Universe (String name, int age, String laws) { super (name, age); this.laws = laws; } void teach () { System.out.println (this.laws + "..."); }
} //. Universe

Và kết quả khi nhấn Run để chạy thử thì chúng ta sẽ thấy thông báo lỗi là nameage được gắn nhãn private nên không khả dụng trong câu lệnh truy xuất từ bên ngoài class Entity ở chương trình main.

Main.java:4: error: name has private access in Entity System.out.println ("Name: " + tabha.name); ^
Main.java:5: error: age has private access in Entity System.out.println ("Age: " + tabha.age); ^
2 errors
exit status 1

Bây giờ chúng ta sẽ sửa lại chương trình main một chút và thay vì truy xuất trực tiếp tới age, chúng ta sẽ gọi phương thức whisper. Phương thức này được class Universe kế thừa từ class Entity, và bởi vì whisper được định nghĩa tại class Entity nên có thể truy xuất được private age được định nghĩa trong class Entity.

class Main { public static void main (String args[]) { Universe tabha = new Universe ("Tabha", 1001, "Buddhism"); tabha.whisper (); } } //. Main
1001 years ago...
Tabha...

Chúng ta đã biết rằng trong JavaScript thì cơ chế hoạt động của publicprivate như đã nói ở trên cũng được biểu hiện tương tự. Mặc định thì tất cả các yếu tố propertymethod đều được JavaScript ngầm định là public; Và từ khóa private của Java thì được JavaScript biểu thị bằng một ký tự # gắn liền phía trước tên định danh của các yếu tố mà chúng ta muốn ẩn đi.

Default & Protected

Hai từ khóa defaultprotected được Java thiết kế với chức năng liên quan tới một khái niệm được gọi là package. Một package trong Java được hiểu đơn giản là một thư mục có chứa các tệp code có liên hệ lẫn nhau. Và nếu một chương trình được viết bằng Java với nhiều tệp code được nhóm về nhiều thư mục khác nhau thì khi đó từ khóa defaultprotected sẽ thể hiện chức năng đóng gói ở cấp độ thư mục hay còn được gọi là package level.

Trong môi trường JavaScript thì chúng ta không có khái niệm đóng gói tương tự ở cấp độ thư mục. Vì vậy nên chúng ta sẽ chỉ quan tâm tới một đặc điểm duy nhất của từ khóa protected trong Java mà chúng ta có thể vay mượn logic hoạt động sang code JavaScript. Đó là các yếu tố được gắn nhãn protected không khả dụng ở mọi nơi như public, nhưng cũng không giống như private chỉ khả dụng duy nhất trong class đang khai báo trực tiếp.

Ngoài phạm vi của class đang định nghĩa trực tiếp, thì các yếu tố protected còn khả dụng đối với code truy xuất được định nghĩa trong các class kế thừa.

Bây giờ chúng ta sẽ thử sửa lại code ví dụ trên và đặt nhãn protected cho các thuộc tính nameage. Sau đó, trong định nghĩa của class Universe, chúng ta sẽ tạo thêm một phương thức echo() và thực hiện truy xuất thông qua con trỏ this.

class Main { public static void main (String args[]) { Universe tabha = new Universe ("Tabha", 1001, "Buddhism"); tabha.echo (); } } //. Main // -- Entity - - - - - - - - - - - - - - - - - - - class Entity { protected String name; protected int age; Entity (String name, int age) { this.name = name; this.age = age; } void whisper () { System.out.println (this.age + " years ago..."); System.out.println (this.name + "..."); }
} //. Entity // -- Universe - - - - - - - - - - - - - - - - - - - class Universe extends Entity { String laws; Universe (String name, int age, String laws) { super (name, age); this.laws = laws; } void teach () { System.out.println (this.laws + "..."); } void echo () { System.out.println ("Name: " + this.name); System.out.println ("Age: " + this.age); System.out.println ("Laws: " + this.laws); }
} //. Universe
Name: Tabha
Age: 1001
Laws: Buddhism

Như chúng ta đã thấy thì nameage được định nghĩa là protected trong class Entity, và khả dụng trong code tham chiếu được định nghĩa trong class Universe.

Để làm rõ điểm khác nhau giữa protectedprivate thì bạn có thể thử chuyển lại các nhãn của nameage thành private. Như vậy trình chạy thử sẽ thông báo lỗi vì phương thức echo() được định nghĩa trong class Universe sẽ không được phép truy xuất tới các yếu tố private của class Entity.

Còn để làm rõ điểm khác nhau giữa protectedpublic thì do giới hạn của công cụ Online REPL đang sử dụng, chúng ta không thể tạo ra một tệp code trong package khác để thử tham chiếu tới các yếu tố protected. Tuy nhiên thì như đã nói trước đó, nếu là code viết ở một tệp khác thư mục với class Universe và không kế thừa class Universe thì chắc chắn sẽ không thể truy xuất được các yếu tố protected.

Protected in JavaScript

Như vậy có một phần logic hoạt động của nhãn protected có thể sẽ hữu ích trong một số trường hợp mà chúng ta có thể mong muốn trong JavaScript. Đó là khả năng đóng gói trong cùng dòng kế thừa tính từ vị trí của class trực tiếp định nghĩa các yếu tố protected.

Code tham chiếu được viết trong chính class đó hoặc các class kế thừa đều có thể truy xuất được các yếu tố protected bằng phép tham chiếu .. Còn lại thì code logic được định nghĩa ở tất cả các nơi khác trong chương trình sẽ không thể truy xuất trực tiếp được các yếu tố protected.

Ở thời điểm hiện tại thì JavaScript chưa hỗ trợ tính năng này. Tuy nhiên khá nhiều lập trình viên cho rằng protected rất quan trọng nên đã tạo ra một quy ước đặt tên với ký hiệu _ gắn ở phía trước cho các yếu tố propertymethod mà họ sẽ không bao giờ truy xuất trực tiếp từ một biến tự tạo.

Tức là các yếu tố có tên dạng như _name, _age, v.v... thì hiển nhiên về mặt kĩ thuật vẫn là public và có thể truy xuất được bởi code định nghĩa ở bất kỳ đâu. Tuy nhiên khi người viết code tự tạo quy ước là sẽ chỉ thực hiện tham yếu tới các yếu tố này duy nhất từ con trỏ this, chứ không từ một biến tự tạo nào khác, thì các yếu tố _ hiển nhiên sẽ có cách hoạt động giống với protected.

// -- Entity - - - - - - - - - - - - - - - - - - - class Entity { constructor (name, age) { this._name = name; this._age = age; } whisper () { console.log (this.age + " years ago..."); console.log (this.name + "..."); }
} //. Entity // -- Universe - - - - - - - - - - - - - - - - - - - class Universe extends Entity { constructor (name, age, laws) { super (name, age); this.laws = laws; } teach () { console.log (this.laws + "..."); } echo () { console.log ("Name: " + this._name); console.log ("Age: " + this._age); console.log ("Laws: " + this.laws); }
} //. Universe // -- Main - - - - - - - - - - - - - - - - - - - var tabha = new Universe ("Tabha", 1001, "Buddhism");
tabha.echo ();

Và như vậy là chúng ta đang có _name_age được định nghĩa trong class Entity, khả dụng trong code truy xuất được định nghĩa trong class Universe kế thừa. Và kèm theo quy ước tự tạo là sẽ không viết code truy xuất từ tên định danh nào khác ngoài con trỏ this.

node main.js Name: Tabha
Age: 1001
Laws: Buddhism

Nguồn tham khảo: Private & Protected _by JavaScript.info

À.. thực ra thì cái quy ước đặt tên cho các yếu tố protected mở đầu với ký hiệu _ vốn được vay mượn từ Python. Ở đó thì cả về khía cạnh kĩ thuật, các yếu tố mở đầu _ thưc sự có khả năng ẩn khỏi code tham chiếu từ bên ngoài dòng kế thừa. Do đó nên người viết code sẽ còn có thể nhận được thông báo lỗi logic vận hành nếu như viết nhầm code tham chiếu từ một tên định danh khác ngoài con trỏ self.

(chưa đăng tải) [JavaScript] Bài 28: Polymorphism in OOP

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 528

- vừa được xem lúc

Bạn đã biết các tips này khi làm việc với chuỗi trong JavaScript chưa ?

Hi xin chào các bạn, tiếp tục chuỗi chủ đề về cái thằng JavaScript này, hôm nay mình sẽ giới thiệu cho các bạn một số thủ thuật hay ho khi làm việc với chuỗi trong JavaScript có thể bạn đã hoặc chưa từng dùng. Cụ thể như nào thì hãy cùng mình tìm hiểu trong bài viết này nhé (go).

0 0 436

- vừa được xem lúc

Một số phương thức với object trong Javascript

Trong Javascript có hỗ trợ các loại dữ liệu cơ bản là giống với hầu hết những ngôn ngữ lập trình khác. Bài viết này mình sẽ giới thiệu về Object và một số phương thức thường dùng với nó.

0 0 158

- vừa được xem lúc

Tìm hiểu về thư viện axios

Giới thiệu. Axios là gì? Axios là một thư viện HTTP Client dựa trên Promise.

0 0 149

- vừa được xem lúc

Imports và Exports trong JavaScript ES6

. Giới thiệu. ES6 cung cấp cho chúng ta import (nhập), export (xuất) các functions, biến từ module này sang module khác và sử dụng nó trong các file khác.

0 0 113

- vừa được xem lúc

Bài toán đọc số thành chữ (phần 2) - Hoàn chỉnh chương trình dưới 100 dòng code

Tiếp tục bài viết còn dang dở ở phần trước Phân tích bài toán đọc số thành chữ (phần 1) - Phân tích đề và những mảnh ghép đầu tiên. Bạn nào chưa đọc thì có thể xem ở link trên trước nhé.

0 0 249