lập trình hướng đối tượng
3.1. Giới thiệu
Với lập trình có cấu trúc, những hệ thống lớn, phức hợp, thì độ phức tạp của chương trình
sẽ tăng lên, sự phụ thuộc của nó vào các kiểu dữ liệu mà nó xử lý cũng tăng theo. Các kiểu dữ
liệu được xử lý trong nhiều thủ tục bên trong chương trình có cấu trúc, và khi có sự thay đổi
trong kiểu dữ liệu thì cũng phải thực hiện thay đổi ở mọi nơi mà dữ liệu đó được sử dụng. Một
nhược điểm nữa của lập trình có cấu trúc là khi có nhiều người tham gia xây dựng chương
trình, mỗi người được giao viết một số hàm riêng biệt nhưng lại có thể sử dụng chung dữ liệu.
Khi có nhu cầu cần thay đổi dữ liệu sẽ ảnh hưởng rất lớn đến công việc của nhiều người.
Lập trình hướng đối tượng dựa trên nền tảng là các đối tượng. Đối tượng được xây dựng
trên cơ sở gắn cấu trúc dữ liệu với các phép toán sẽ thể hiện được đúng cách mà chúng ta suy
nghĩ, bao quát về thế giới thực. Chẳng hạn, ô tô có bánh xe, di chuyển được và hướng của nó
thay đổi được bằng cách thay đổi tay lái. Tương tự, cây là loại thực vật có thân gỗ và lá. Cây
không phải là ô tô và những gì thực hiện được với ô tô sẽ không làm được với cây.
Lập trình hướng đối tượng cho phép chúng ta kết hợp những tri thức bao quát về các quá
trình với những khái niệm trừu tượng được sử dụng trong máy tính. Chương trình hướng đối
tượng xác định chính xác các đặc trưng và hành vi của các kiểu dữ liệu, trong đó có thể tạo ra
những đối tượng mới được xây dựng từ những khuôn khổ có sẵn hay tổ hợp để tạo ra những
đặc trưng mới.
Trong chương này chúng ta sẽ giới thiệu những khái niệm cơ bản và các bước cần thực hiện
trong lập trình hướng đối tượng.
3.2. Lập trình hướng thủ tục (chức năng)
Những ngôn ngữ lập trình bậc cao truyền thống như COBOL, FOTRAN, PASCAL, C v.v...,
được gọi chung là ngôn ngữ lập trình hướng thủ tục. Theo cách tiếp cận hướng thủ tục thì một
hệ thống phần mềm được xem như là dãy các công việc cần thực hiện như đọc dữ liệu, tính
toán, xử lý, lập báo cáo và in ấn kết quả v.v... Mỗi công việc đó sẽ được thực hiện bởi một số
hàm nhất định. Như vậy trọng tâm của cách tiếp cận này là các hàm chức năng. Cấu trúc của
chương trình được xây dựng theo cách tiếp cận hướng thủ tục có dạng như hình 3-1.
Hình 3-1. Cấu trúc của chương trình hướng thủ tục
Lập trình hướng thủ tục (LTHTT) sử dụng kỹ thuật phân rã hàm chức năng theo cách tiếp
cận top-down để tạo ra cấu trúc phân cấp. Chương trình được xây dựng theo cách tiếp cận
Chương trình chính
MAIN()
H m_6à
H m_1à
H m_3à
H m_2à
H m_9àH m_8à
H m_7à
H m_4à
H m_5à
hướng thủ tục thực chất là danh sách các câu lệnh mà theo đó máy tính cần thực hiện. Danh
sách các lệnh đó được tổ chức thành từng nhóm theo đơn vị cấu trúc cú pháp của ngôn ngữ đặc
tả hay ngôn ngữ lập trình và được gọi là hàm (hay thủ tục). Để mô tả các hoạt động của các
hàm, các dòng điều khiển và dữ liệu từ hoạt động này sang hoạt động khác người ta thường
dùng sơ đồ khối.
Khi tập trung vào trọng tâm phát triển các hàm thì chúng ta lại ít chú ý đến dữ liệu, những
cái mà các hàm sư dụng để thực hiện công việc của mình. Cái gì sẽ xảy ra đối với dữ liệu và
gắn dữ liệu với các hàm như thế nào? cùng nhiều vấn đề khác cần phải giải quyết khi chúng ta
muốn xây dựng các phương pháp thích hợp để phát triển hệ thống trong thế giới thực. Trong
chương trình có nhiều hàm, thường thì có nhiều thành phần dữ liệu quan trọng sẽ được khai
báo tổng thể (global) để cho nhiều hàm có thể truy nhập, đọc và làm thay đổi giá trị của biến
tổng thể. Mỗi hàm có thể có vùng dữ liệu riêng còn gọi là dữ liệu cục bộ (local). Mối quan hệ
giữa dữ liệu và hàm trong chương trình hướng thủ tục được mô tả trong hình 3-2.
Hình 3-2. Quan hệ dữ liệu và hàm trong LTHTT
Nhiều hàm có thể truy nhập, sử dụng dữ liệu chung, làm thay đổi giá trị của chúng và vì vậy
rất khó kiểm soát. Nhất là đối với các chương trình lớn, phức tạp thì vấn đề càng trở nên khó
khăn hơn.
Khi chúng ta muốn thay đổi, bổ sung cấu trúc dữ liệu dùng chung cho một số hàm thì chúng
ta phải thay đổi hầu như tất cả các hàm liên quan đến dữ liệu đó.
Ngoài những trở ngại mà chúng ta đã nêu ở trên thì mô hình được xây dựng theo cách tiếp
cận hướng thủ tục không mô tả được đầy đủ, trung thực hệ thống trong thực tế. Bởi vì cách đặt
trọng tâm vào hàm là hướng tới hoạt động sẽ không thực sự tương ứng với các thực thể trong
hệ thống của thế giới thực.
Tóm lại những đặc tính chính của lập trình hướng thủ tục là:
+ Tập trung vào công việc cần thực hiện (thuật toán).
+ Chương trình lớn được chia thành các hàm nhỏ hơn.
+ Phần lớn các hàm sử dụng dữ liệu chung.
+ Dữ liệu trong hệ thống được chuyển động từ hàm này sang hàm khác.
+ Hàm biến đổi dữ liệu từ dạng này sang dạng khác.
+ Sử dụng cách tiếp cận top-down trong thiết kế chương trình.
3.3. Lập trình hướng đối tượng
Như ở các phần trước chúng ta đã nêu, để giải quyết được những vấn đề tồn tại trong công
nghệ phần mềm thì chúng ta cần phải sử dụng những phương pháp, công cụ thích hợp để phát
619 620
Dữ liệu chung
(Global)
Dữ liệu chung
(Global)
H m_2à
Dữ liệu riêng
(Local)
H m_3à
Dữ liệu riêng
(Local)
H m_1à
Dữ liệu riêng
(Local)
triển phần mềm. Trong các mục
§
1 và
§
2 chúng ta đã đề cập đến phương pháp phân tích, thiết
kế hướng đối tượng. Trong mục này chúng ta tiếp tục nghiên cứu về phương pháp lập trình
hướng đối tượng.
Lập trình hướng đối tượng đặt trọng tâm vào đối tượng, yếu tố quan trọng trong quá trình
phát triển chương trình và nó không cho phép dữ liệu chuyển động tự do trong hệ thống. Dữ
liệu được gắn chặt với từng hàm thành các vùng riêng mà các hàm đó tác động lên và nó được
bảo vệ cấm các hàm bên ngoài không được truy nhập một cách tuỳ tiện. LTHĐT cho phép
chúng ta phân tích bài toán thành tập các thực thể được gọi là các đối tượng và sau đó xây
dựng các dữ liệu cùng với các hàm xung quanh các đối tượng đó. Tổ chức dữ liệu và hàm trong
các chương trình hướng đối tượng được mô tả như trong hình 3-3.
Đối tượng A Đối tượng B
Dữ liệu Dữ liệu
Hàm Hàm
Đối tượng C
Dữ liệu
Hàm
Hình 3-3. Tổ chức dữ liệu và hàm trong chương trình HĐT
Dữ liệu của một đối tượng chỉ có thể được truy nhập bởi chính các hàm xác định trong đối
tượng đó. Tuy nhiên các hàm của đối tượng này có thể truy nhập tới các hàm của đối tượng
khác, nghĩa là các đối tượng trao đổi với nhau thông qua việc trao đổi thông báo. Lập trình
hướng đối tượng có những đặc tính chủ yếu sau:
1. Tập chung vào dữ liệu thay cho các hàm.
2. Chương trình được chia thành các đối tượng.
3. Các cấu trúc dữ liệu được thiết kế sao cho đặc tả được các đối tượng.
4. Các hàm xác định trên các vùng dữ liệu của đối tượng được gắn với nhau trên cấu trúc dữ
liệu đó.
5. Dữ liệu được bao bọc, che giấu và không cho phép các hàm ngoại lai truy nhập tự do.
6. Các đối tượng trao đổi với nhau thông qua các hàm.
7. Dữ liệu và các hàm mới có thể dễ dàng bổ sung vào đối tượng nào đó khi cần thiết.
8. Chương trình được thiết kế theo cách tiếp cận bottom-up (dưới-lên).
Lập trình hướng đối tượng là khái niệm mới và được hiểu rất khác nhau đối với nhiều
người. ở đây chúng ta có thể hiểu lập trình hướng đối tượng là cách tiếp cận để phân chia
chương trình thành các đơn thể (module) bằng cách tạo ra các vùng bộ nhớ cho cả dữ liệu lẫn
hàm và chúng sẽ được sử dụng như các mẫu để tạo ra bản sao từng đơn thể khi cần thiết. Đối
tượng ở đây được xem như là vùng phân chia bộ nhớ trong máy tính để lưu trữu dữ liệu và tập
các hàm tác động trên dữ liệu gắn với chúng. Bởi vì các vùng phân hoạch bộ nhớ là độc lập với
nhau nên các đối tượng có thể sử dụng bởi nhiều chương trình khác nhau mà không ảnh hưởng
lẫn nhau.
Khái niệm "hướng đối tượng" nhiều người hiểu rất khác nhau. Vì vậy, để hiểu rõ bản chất
và có thể đi đến thống nhất quan điểm, chúng ta cần phải nghiên cứu kỹ những khái niệm cơ
bản trong LTHĐT. Trong phần này chúng ta đề cập đến những khái niệm sau:
621 622
1. Đối tượng
2. Lớp
3. Trừu tượng hoá dữ liệu
4. Kế thừa
5. Tương ứng bội
6. Liên kết động
7. Truyền thông báo
Đối tượng
Trong các mục trước chúng ta đã nêu cách xác định đối tượng trong quá trình phân tích và
thiết kế hướng đối tượng. ở đây chúng ta tìm hiểu chi tiết hơn để hiểu rõ vai tò của đối tượng
trong cách tiếp cận hướng đối tượng nói chung và LTHĐT nói riêng.
Đối tượng là thực thể được xác định trong thời gian hệ thống hướng đối tượng hoạt động.
Như vậy đối tượng có thể biểu diễn là con người, vật, hay một bảng dữ liệu hoặc bất kỳ một
hạng thức nào đó cần xử lý trong chương trình. Đối tượng cũng có thể là các dữ liệu được định
nghĩa bởi người sử dụng (người lập trình) như vector, danh sách, các record v.v... Nhiệm vụ
của LTHĐT là phân tích bài toán thành các đối tượng và xác định được bản chất của sự trao
đổi thông tin giữa chúng. Đối tượng trong chương trình cần phải được chọn sao cho nó thể
hiện được một cách gần nhất so với những thực thể trong thế giới thực.
Khi chương trình thực hiện, các đối tượng sẽ trao đổi với nhau bằng cách gửi hay nhận
thông báo. Ví dụ BAN_DOC và CHO_MUON là hai đối tượng trong hệ thống thư viện, đối
tượng BAN_DOC có thể gửi một thông báo (bằng phiếu yêu cầu chẳng hạn) cho đối tượng
CHO_MUON yêu cầu mượn cuốn "Lập trình hướng đối tượng với c++". Mỗi đối tượng có dữ
liệu và các hàm để xử lý dữ liệu đó. Các đối tượng trao đổi với nhau mà không cần biết chi tiết
về dữ liệu và các thuật toán xử lý của đối tượng khác. Để trao đổi được với nhau, mỗi đối
tượng chỉ cần biết kiểu thông báo mà nó nhận và kiểu thông báo mà nó sẽ gửi cho các đối
tượng khác.
Các lớp đối tượng
Như trên chúng ta đã xác định, đối tượng trong chương trình gồm cả dữ liệu và các hàm xử
lý trên dữ liệu đó. Một tập dữ liệu và các hàm của một đối tượng có thể được xem như một
kiểu dữ liệu được định nghĩa bởi người sử dụng. Kiểu dữ liệu ở đây được gọi là lớp (class).
Trong lập trình, các đối tượng là các biến có kiểu class. Khi một lớp được định nghĩa, thì nó có
thể tạo ra số lượng các đối tượng tuỳ ý của lớp đó. Như vậy, TOA, LE, BUOI, CAM là các loại
quả trong lớp HOA_QUA. Lớp là kiểu được người sử dụng định nghĩa và nó cũng có các tính
chất như các kiểu chuẩn integer, float trong các ngôn ngữ lập trình. Tương tự như kiểu dữ liệu
đã được định nghĩa trong chương trình, lệnh khai báo
HOA_QUA TAO;
sẽ tạo ra đối tượng TAO trong lớp HOA_QUA.
Trừu tượng hoá dữ liệu và bao gói thông tin
Việc đóng gói dữ liệu và các hàm vào một đơn vị cấu trúc (được gọi là lớp) được xem như
một nguyên tắc bao gói (che giấu) thông tin. Dữ liệu được tổ chức sao cho thế giới bên ngoài
(các đối tượng ở lớp khác) không truy nhập được vào mà chỉ cho phép các hàm trong cùng lớp
hoặc trong những lớp có quan hệ kế thừa với nhau được quyền truy nhập. Chính các hàm thành
phần của lớp sẽ đóng vai trò như là giao diện giữa dữ liệu của đối tượng và phần còn lại của
chương trình. Nguyên tắc bao gói dữ liệu để ngăn cấm sự truy nhập trực tiếp trong lập trình
623 624
được gọi là sự che giấu thông tin.
Trừu tượng hoá là cách biểu diễn những đặc tính và bỏ qua những chi tiết vụn vặt hoặc
những giải thích. Để xây dựng các lớp, chúng ta phải sử dụng khái niệm trừu tượng hoá. Ví dụ
chúng ta có thể định nghĩa một lớp là danh sách các thuộc tính trừu tượng như là kích thước,
hình dáng, mầu và các hàm xác định trên các thuộc tính này để mô tả các đối tượng trong
không gian hình học. Trong lập trình, lớp sử dụng như kiểu dữ liệu trừu tượng.
Kế thừa
Kế thừa là quá trình mà các đối tượng của lớp này được quyền sử dụng một số tính chất của
các đối tượng của lớp khác. Nguyên lý kế thừa hỗ trợ cho việc tạo ra cấu trúc phân cấp các lớp.
Ví dụ, một trường đại học đào tạo sinh viên theo ba khối: Xã hội, Công nghệ, và Khoa học cơ
bản. Mỗi khối lại có các khoa. Khối công nghệ có các khoa: Cơ khí, Điện, Máy dân dụng; còn
khối Khoa học cơ bản có các khoa: Toán, Lý, Hoá, Sinh. Hệ thống sẽ tổ chức thành cấu trúc
phân cấp các lớp kề nhau như sau:
Hình 3.4. Cấu trúc phân cấp các lớp trong quân hệ kế thừa
Lớp SINH_VIEN mô tả những thuộc tính chung nhất của sinh viên tất cả các khối trong
trường ví dụ như: Họ và tên, quê, tuổi. Những đặc tính đó được kế thừa ở trong các lớp
XA_HOI, CONG_NGHE, CO_BAN. Các lớp dẫn xuất đó được bổ sung thêm những thuộc
tính, các hàm tương ứng mô tả cho sinh viên. Các lớp XA_HOI, CONG_NGHE, CO_BAN
được bổ sung thêm những thuộc tính mới để phân biệt giữa các khối với nhau. Trong khối
CO_BAN lại chia thành nhiều khoa như: TOAN, LY, HOA, SINH; khối CONG_NGHE chia
thành các khoa: CO_KHI, DIEN và MAY_DD. Những lớp sau có những thuộc tính mô tả cho
sinh viên của từng khoa.
Trong LTHĐT, khái niệm kế thừa kéo theo ý tưởng sử dụng lại. Nghĩa là từ một lớp đã được
xây dựng chúng ta có thể bổ sung thêm một số tính chất tạo ra một lớp mới kế thừa lớp cũ mà
không làm thay đổi những cái đã có.
Khái niệm kế thừa được hiểu như cơ chế sao chép ảo không đơn điệu. Trong thực tế, mọi
việc xảy ra tựa như những lớp cơ sở đều được sao vào trong lớp con (lớp dẫn xuất) mặc dù
điều này không được cài đặt tường minh (nên gọi là sao chép ảo) và việc sao chép chỉ thực
hiện đối với những thông tin chưa được xác định trong các lớp cơ sở (sao chép không đơn
điệu). Do vậy, có thể diễn đạt cơ chế kế thừa như sau:
1. Lớp A kế thừa lớp B sẽ có (không tường minh) tất cả các thuộc tính, hàm đã được xác
định trong B.
2. Bổ sung thêm một số thuộc tính, hàm để mô tả được đúng các hành vi của những đối
tượng mà lớp A quản lý.
SINH_VIEN
CO_BAN
XA_HOI
CONG_NGHE
SINHHOALY
TOAN
MAY_DD
DIEN
CO_KHI
625 626