Property vs Method
Một trong những nguyên tắc của LTHDT là che gốc dữ kiện (data hiding). Nguyên tắc này đặt căn bản trên câu "cái gì của tôi là của riêng tôi, bạn muốn biết nó thì hỏi tôi chứ không được trực tiếp tò mò".
Ví dụ, hàng xóm ta là ông X. Nếu muốn biết ông X có bao nhêu tiền thì ta không thể chạy vào ngân hàng hỏi tài khoản của ông. Cách duy nhất là hỏi thẳng ông ta, và ông sẽ cho biết: "trong ngân hàng tôi, số kết là ….$"
Trong bài trên cũng vậy, tên SV là dữ liệu riêng của đối tượng Sinh Viên, các phần code khác không được (không nên) thọc thẳng vào, mà phải hỏi chính SV này.
(Xin lỗi phần sau đây không có vd Java, vì lâu ngày không đụng tới, quên mất tiêu rồi. Chỉ nói C++ vá C# thôi – VB rất giống C# nên không cần phải thêm)
Để thể hiện lý thuyết này, người viết lớp (class) gần như luôn luôn đặt các data members (fields, biến dữ liệu) là private.
C++ không có khái niệm property nên trong lớp, mỗi field cần phải có it nhất một hàm (method) để xuất trị và một hàm để nhập trị. Muốn biết trị của một biến private trong lớp, người ta gọi hàm xuất trị và muốn thay đổi tri người ta gọi hàm nhập trị.
C# đặt thêm property để làm giản tiện hơn. Mỗi field đi kèm với một property, trong cái property này sẽ có một hàm get và một hàm set, tương đương với hai hàm xuất và nhập trong C++.
Chú ý:
1. Các field thực sự private, tức là chỉ dùng trong lớp mà không cần phải bộc lộ ra ngoài thì sẽ không có property (không có hàm nhập và xuất, C++). Các field chỉ cho nhập mà không cho xuất thì property chỉ có set chứ không có get. Tương tự, nếu property có get mà không có set thì field này chỉ cho xuất , không cho nhập (thường dùng cho constant).
2. Property không nhất thiết phải đi cặp với một field. Thí dụ lớp của bạn thay vì dùng 1 field tênV, đổi lại dùng 1 field Họ và 1 field Tên, bạn có quyền viết một property
HoVaTen {
get { return Họ + " " + Tên; { set { Họ = TachChuoiLayHo(value); Tên = TachChuoiLayTen(value); }
} // nhiệm vụ của set là tách họ và tên ra từ chuỗi nhập (value), ghi vào hai field Họ, Tên
Bạn cũng cần viết thêm hai hàm
private string TachChuoiLayHo(string s) { … } và
private string TachChuoiLayTen(string s) { … }
(nếu sai syntax một chút, xin thông cảm.)
Tại sao lại phải rắc rối dấu data làm gì? Sau khi thiết kế (design) nhiều lớp rồi bạn sẽ thấy giá trị. Trước mắt là thí dụ của bài Danh Mục Sinh Viên trên. Ta chỉ cần sửa tên các fields (đặt thêm dấu gạch vào đầu) là xong. Các chương trình dùng đến lớp này và các lớp di truyền từ lớp này không cần biết đến điều đó. Chúng chỉ cần biết rằng giao diện công (public exposure* – gồm public properties và public methods) của lớp không hề thay đổi.
Dùng thí dụ ông X. Khi bạn hỏi, ông có thể chỉ cho bạn biết số kết của 1 vài tài khoản, không có gì bắt buộc ông phải cho bạn biết hết. Trừ phi bạn là kiểm toán, được quyền đi thẳng vào lục tất cả các chứng từ (trường hợp này C++ có lớp 'friend', nhưng C# không có, thực hiện rất rắc rối)
* Chữ giao diện thực ra tiếng Anh là interface, nhưng ở đây nói trại đi thành public exposure với mục đích tránh lẫn lộn với chữ interface dùng để chỉ lớp giao diện trong C# (Java?)
--- Theo đúng ngôn từ của OOP thì 'che dấu dữ kiện' là 'đóng gói', tiếng Anh là 'information hiding' hoặc 'encapsulation'. Ở đây dùng 'data hiding' là để nhấn mạnh chỗ dữ liệu
bigbelly:
Tại sao dùng private methods?
Thí dụ trên, bạn để ý thấy hai hàm TachChuoiLayHo và TachChuoiLayTen được cho là private. Chúng không cần được biết tới ngoài lớp. Bởi vì lớp Student muốn xác định một điểm rằng "tôi chỉ nhập một chuỗi có họ và tên, và khi bạn hỏi, tôi trả lời họ tên thôi, chứ tôi làm gì với chuỗi đó (tách ra thành họ và tên và giữ riêng trong 2 biến riêng biệt), bạn không cần biết tới."
Về sau, khi tác giả muốn sửa lại hai hàm này thì cứ việc thẳng tay sửa. Nếu tác giả lỡ đặt chúng public, mỗi lần sửa, bắt buộc phải xem lại có lớp nào kế thừa lóp này và có code nào dùng lớp này hay không để chỉnh luôn. Một hệ thống lớn có hàng trăm, hàng ngàn lớp. Chỉnh không phải là chuyện đùa.


