Giới thiệu
• Phân tích thiết kế và lập trình theo hướng đối tượng tuy sinh sau đẻ
muộn nhưng đã chứng tỏ được những ưu điểm vượt trội so với cách tiếp cận cổ điển. Trong lĩnh vực phân tích và thiết kế hệ thống, hướng tiếp cận mới mẻ này đã thu hút nhiều nhà nghiên cứu tên tuổi. Nhiều kiểu mẫu, phương pháp luận, mô hình phân tích đã được đưa ra với những mức độ thành công khác nhau. Ta sẽ nghiên cứu phương hướng phân tích theo quan điểm của Rumbaugh: Mô hình hoá và thiết kế theo hướng đối tượng.
Phương pháp phân tích bằng mô hình,
Phân tích dựa trên CƠ SỞ mô hình hóa các đối tượng trong thế giới thực.
Dùng mô hình để xây dựng một thiết kế không phụ
thuộc ngôn ngữ được tổ chức xung quanh các đối tượng. So với cách tổ chức cổ điển, mô hình hoá và thiết kế hướng đối tượng giúp hiểu rõ hơn yêu cầu của vấn đề, thiết kế trong sáng hơn, và kết quả là những hệ thống dễ dàng bảo trì hơn.
118 trang |
Chia sẻ: candy98 | Lượt xem: 563 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Bài giảng Lập trình hướng đối tượng - Ôn tập tốt nghiệp - Chương 1: Đối tượng và lớp, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Lập Trình Hướng Đối Tượng
Ôn tập tốt nghiệp
Chương 1
Đối tượng và lớp
Giới thiệu
Phân tích thiết kế và lập trình theo hướng đối tượng tuy sinh sau đẻ
muộn nhưng đã chứng tỏ được những ưu điểm vượt trội so với cách
tiếp cận cổ điển.
Trong lãnh vực phân tích và thiết kế hệ thống, hướng tiếp cận mới
mẻ này đã thu hút nhiều nhà nghiên cứu tên tuổi. Nhiều kiểu mẫu,
phương pháp luận, mô hình phân tích đã được đưa ra với những
mức độ thành công khác nhau.
Ta sẽ nghiên cứu phương hướng phân tích theo quan điểm của
Chương 2- Lớp và đối tượng 3
Rumbaugh: Mô hình hoá và thiết kế theo hướng đối tượng.
Phương pháp phân tích bằng mô hình
Phân tích dựa trên cơ sở mô hình hóa các đối tượng
trong thế giới thực.
Dùng mô hình để xây dựng một thiết kế không phụ
thuộc ngôn ngữ được tổ chức xung quanh các đối tượng.
So với cách tổ chức cổ điển, mô hình hoá và thiết kế
hướng đối tượng giúp hiểu rõ hơn yêu cầu của vấn đề,
Chương 2- Lớp và đối tượng 4
thiết kế trong sáng hơn, và kết quả là những hệ thống
dễ dàng bảo trì hơn.
Phương pháp phân tích bằng mô hình
Các khái niệm trong thế giới thực được mô hình hoá
bằng các ký hiệu đồ hoạ mô tả các đối tượng của chúng
(cấu trúc dữ liệu và hành vi) độc lập với ngôn ngữ.
Các khái niệm và ký hiệu này có thể được dùng thống
nhất suốt quá trình phát triển hệ thống từ phân tích,
thiết kế đến cài đặt mà không cần thay đổi qua các giai
đoạn như một số phương pháp luận khác.
Chương 2- Lớp và đối tượng 5
Không quan tâm đến chi tiết cài đặt cho đến giai đoạn
cuối của qui trình phát triển hệ thống.
Phương pháp phân tích bằng mô hình
Các khái niệm liên quan đến máy tính chỉ được đưa ra
ở bước mã hóa sau cùng, nhờ đó giữ được sự uyển
chuyển, linh động và có được tự do quyết định trong giai
đoạn phân tích và thiết kế.
Chương 2- Lớp và đối tượng 6
Phương pháp luận hướng đối tượng
Mô hình hóa và thiết kế theo hướng đối tượng là một lối
suy nghĩ mới về vấn đề cần giải quyết dùng các mô
hình được tổ chức xung quanh các khái niệm trong thế
giới thực.
Trong một hệ thống thông tin hướng đối tượng, mọi thứ,
hay hầu như mọi thứ, được quan điểm như các đối
tượng.
Chương 2- Lớp và đối tượng 7
Mỗi đối tượng là sự kết hợp của cả hai thành phần đặc
trưng là cấu trúc dữ liệu (các thuộc tính) và hoạt động
(các thủ tục xử lý dữ liệu).
Phương pháp luận hướng đối tượng
Phương pháp luận theo quan điểm của J.Rumbaugh bao
gồm xây dựng một mô hình của hệ thống trong lãnh vực
ứng dụng và thêm chi tiết cài đặt trong quá trình thiết
kế hệ thống.
Các ký hiệu đồ họa được sử dụng để biểu diễn các khái
niệm hướng đối tượng.
Chương 2- Lớp và đối tượng 8
Cách tiếp cận này được gọi là kỹ thuật thiết kế bằng mô
hình (OMT: Object Modeling Technique).
Phương pháp luận hướng đối tượng
Kỹ thuật mô hình hoá OMT bao gồm các bước:
Phân tích Thiết kế
hệ thống
Thiết kế
đối tượng
Cài đặt
Chương 2- Lớp và đối tượng 9
Các khái niệm hướng đối tượng
Trừu tượng hoá :
• Nhấn mạnh vào các khía cạnh cốt yếu vốn có của một thực thể
và bỏ qua những tính chất riêng biệt.
• Sử dụng trừu tượng hoá trong phân tích có nghĩa là làm việc với
các khái niệm trong lãnh vực ứng dụng và bỏ qua chi tiết cài
đặt.
• Hầu hết các ngôn ngữ lập trình hiện đại đều hổ trợ trừu tượng
Chương 2- Lớp và đối tượng 10
hoá. Nhưng sự trừu tượng hóa được tận dụng trong tiếp cận đối
tượng với tính kế thừa (inheritance) và tính đa dạng
(polymorphism) mang lại hiệu quả cao hơn.
Các khái niệm hướng đối tượng
Tính đóng gói :
• Tách rời các khía cạnh giao diện với bên ngoài của đối tượng
với chi tiết cài đặt bên trong.
• Tính đóng gói ngăn chặn khả năng một chương trình trở nên
quá phụ thuộc lẫn nhau dẫn tới hậu quả một sự thay đổi nhỏ
có thể ảnh hưởng lớn đến toàn bộ hệ thống.
• Trong tiếp cận O.O. khả năng kết hợp dữ liệu và hành vi trong
Chương 2- Lớp và đối tượng 11
một thực thể duy nhất giúp cho tính đóng gói rõ ràng hơn và
hiệu quả hơn.
Các khái niệm hướng đối tượng
Kết hợp dữ liệu và hành vi:
• Trong cách tiếp cận thủ tục cổ điển, hệ thống được xây dựng
trên hai sơ đồ phân cấp chằng chịt: sơ đồ phân cấp dữ liệu và
sơ đồ phân cấp thủ tục, trong đó sự liên hệ giữa một loại dữ liệu
và các thủ tục xử lý dữ liệu rất mờ nhạt, dẫn đến khó khăn
trong việc sửa chữa, nâng cấp trong tương lai.
• Cách tiếp cận O.O. loại bỏ những nhược điểm kể trên bằng
Chương 2- Lớp và đối tượng 12
cách kết hợp dữ liệu và phần thủ tục xử lý dữ liệu vào trong một
thực thể duy nhất, hệ thống trở thành một sơ đồ phân cấp duy
nhất các lớp đối tượng.
Các khái niệm hướng đối tượng
Sơ đồ phân cấp dữ liệu
Kết hợp dữ liệu và hành vi
Chương 2- Lớp và đối tượng 13
Sơ đồ phân cấp lớp
Sơ đồ phân cấp thủ tục
Được thay bằng
Đối tượng và lớp
Ta định nghĩa một đối tượng là một "cái gì đó" có ý
nghĩa cho vấn đề ta quan tâm. Đối tượng phục vụ hai
mục đích: Giúp hiểu rõ thế giới thực và cung cấp cơ sở
cho việc cài đặt trong máy.
Mỗi đối tượng có một nét nhận dạng để phân biệt nó
với các đối tượng khác. Nét nhận dạng mang ý nghĩa
các đối tượng được phân biệt với nhau do sự tồn tại vốn
Chương 2- Lớp và đối tượng 14
có của chúng chứ không phải các tính chất mà chúng
có.
Đối tượng và lớp
Các đối tượng có các đặc tính tương tự nhau được gom
chung lại thành lớp đối tượng. Ví dụ Người là một lớp
đối tượng. Một lớp đối tượng được đặc trưng bằng các
thuộc tính, và các hoạt động (hành vi).
Một thuộc tính (attribute) là một giá trị dữ liệu cho mỗi
đối tượng trong lớp. Tên, Tuổi, Cân nặng là các thuộc
tính của Người.
Chương 2- Lớp và đối tượng 15
Một thao tác (operation) là một hàm hay một phép biến
đổi có thể áp dụng vào hay áp dụng bởi các đối tượng
trong lớp.
Sơ đồ đối tượng
Ta dùng sơ đồ đối tượng để mô tả các lớp đối tượng. Sơ
đồ đối tượng bao gồm sơ đồ lớp và sơ đồ thể hiện.
Sơ đồ lớp mô tả các lớp đối tượng trong hệ thống, một
lớp đối tượng được diễn tả bằng một hình chữ nhật có 3
phần: phần đầu chỉ tên lớp, phần thứ hai mô tả các
thuộc tính và phần thứ ba mô tả các thao tác của các
đối tượng trong lớp đó.
Chương 2- Lớp và đối tượng 16
Sơ đồ lớp và sơ đồ thể hiện
Sinh viên
Họ tên
Năm sinh
Mã số
Điểm TB
(Sinh viên)
Nguyễn Văn A
1984
0610234T
9.2
Tên lớp
Thuộc tính
Chương 2- Lớp và đối tượng 17
Đi học
Đi thi
Phân loại
Thao tác
Sơ đồ lớp Sơ đồ thể hiện
Đối tượng và lớp
Cùng một thao tác có thể được áp dụng cho nhiều lớp
đối tượng khác nhau, một thao tác như vậy được gọi là
có tính đa dạng (polymorphism).
Mỗi thao tác trên mỗi lớp đối tượng cụ thể tương ứng với
một cài đặt cụ thể khác nhau. Một cài đặt như vậy được
gọi là một phương thức (method).
Một đối tượng cụ thể thuộc một lớp được gọi là một thể
hiện (instance) của lớp đó. Joe Smith, 25 tuổi, nặng
Chương 2- Lớp và đối tượng 18
58kg, là một thể hiện của lớp người.
Cài đặt lớp trong C++
Lớp trong C++ là cài đặt của kiểu dữ liệu trừu tượng do
người sử dụng định nghĩa, cho phép kết hợp dữ liệu, các
phép toán, các hàm liên quan để tạo ra một đơn vị
chương trình duy nhất. Các lớp này có đầy đủ ưu điểm và
tiện lợi như các kiểu dữ liệu nội tại. Lớp tách rời phần
giao diện (chỉ liên quan với người sử dụng) và phần cài
đặt lớp.
Chương 2- Lớp và đối tượng 19
Lớp trong C++ được cài đặt sử dụng từ khoá struct và
class.
Ví dụ so sánh: Xây dựng kiểu dữ liệu stack.
1. Cách tiếp cận cổ điển:
// Stack1.cpp :
//Dung cau truc va ham toan cuc
#include
typedef int bool;
typedef int Item;
const bool false = 0, true = 1;
Chương 2- Lớp và đối tượng 20
struct Stack
{
Item *st, *top;
int size;
};
Ví dụ so sánh (tt)
void StackInit(Stack *ps, int sz)
{
ps->st = ps->top = new Item[ps->size=sz];
}
void StackCleanUp(Stack *ps)
{
delete [] ps->st;
Chương 2- Lớp và đối tượng 21
}
bool StackFull(Stack *ps)
{
return (ps->top - ps->st >= ps->size);
}
Ví dụ so sánh (tt)
bool StackEmpty(Stack *ps)
{
return (ps->top st);
}
bool StackPush(Stack *ps, Item x)
{
Chương 2- Lớp và đối tượng 22
if (StackFull(ps)) return false;
*ps->top++ = x;
return true;
}
Ví dụ so sánh (tt)
bool StackPop(Stack *ps, Item *px)
{
if (StackEmpty(ps)) return false;
*px = *--ps->top;
return true;
}
Chương 2- Lớp và đối tượng 23
Ví dụ so sánh (tt)
void XuatHe16(long n)
{
static char hTab[] = “0123456789ABCDEF”;
Stack s;
StackInit(&s,8);
int x;
do {
StackPush(&s, n%16);
Chương 2- Lớp và đối tượng 24
n /= 16;
} while(n);
while(StackPop(&s,&x))
cout << hTab[x];
StackCleanUp(&s);
}
Ví dụ so sánh (tt)
Nhận xét:
Giải quyết được vấn đề.
Khai báo cấu trúc dữ liệu nằm riêng, các hàm xử lý dữ
liệu nằm riêng ở một nơi khác. Do đó khó theo dõi
quản lý khi hệ thống lớn. Vì vậy khó bảo trì.
Mọi thao tác đều có tham số đầu tiên là con trỏ đến đối
tượng cần thao tác. Tư tưởng thể hiện ở đây là hàm hay
Chương 2- Lớp và đối tượng 25
thủ tục đóng vai trò trọng tâm. Đối tượng được gởi đến
cho hàm xử lý.
Trình tự sử dụng qua các bước: Khởi động, sử dụng thực
sự, dọn dẹp.
Ví dụ so sánh (tt)
2. Cách tiếp cận dùng hàm thành phần:
//...
struct Stack
{
Item *st, *top;
int size;
void Init(int sz) {st = top = new
Item[size=sz];}
Chương 2- Lớp và đối tượng 26
void CleanUp() {if (st) delete [] st;}
bool Full() const {return (top - st >=
size);}
bool Empty() const {return (top <= st);}
bool Push(Item x);
bool Pop(Item *px);
};
Ví dụ so sánh (tt)
bool Stack::Push(Item x)
{
if (Full()) return false;
*top++ = x;
return true;
}
Chương 2- Lớp và đối tượng 27
bool Stack::Pop(Item *px)
{
if (Empty()) return false;
*px = *--top;
return true;
}
Ví dụ so sánh (tt)
void XuatHe16(long n)
{
static char hTab[] = “0123456789ABCDEF”;
Stack s;
s.Init(8);
int x;
do {
Chương 2- Lớp và đối tượng 28
s.Push(n%16);
n /= 16;
} while(n);
while(s.Pop(&x))
cout << hTab[x];
s.CleanUp();
}
Ví dụ so sánh (tt)
Nhận xét:
Giải quyết được vấn đề.
Dữ liệu và các hàm xử lý dữ liệu được gom vào một chỗ
bên trong cấu trúc. Do đó dễ theo dõi quản lý, dễ bảo trì
nâng cấp.
Các thao tác đều bớt đi một tham số so với cách tiếp cận
cổ điển. Vì vậy việc lập trình gọn hơn. Tư tưởng thể hiện
Chương 2- Lớp và đối tượng 29
ở đây là đối tượng đóng vai trò trọng tâm. Đối tượng
thực hiện thao tác trên chính nó.
Trình tự sử dụng qua các bước: Khởi động, sử dụng thực
sự, dọn dẹp.
Các hàm thành phần.
Là hàm được khai báo trong lớp. Hàm thành phần có thể
được định nghĩa bên trong hoặc bên ngoài lớp.
Hàm thành phần có nghi thức giao tiếp giống với các
hàm bình thường khác: có tên, danh sách tham số, giá trị
trả về.
Gọi hàm thành phần bằng phép toán dấu chấm (.) hoặc
dấu mũi tên (->).
Chương 2- Lớp và đối tượng 30
Stack s, *ps = &s;
s.Init(10);
for (int i = 0; i < 20; i++)
ps->Push(i);
Lớp
Trong cách tiếp cận dùng struct và hàm thành phần,
người sử dụng có toàn quyên truy xuất, thay đổi các
thành phần dữ liệu của đối tượng thuộc cấu trúc. Ví dụ:
Stack s;
s.Init(10);
s.size = 100; // Nguy hiem
for (int i = 0; i < 20; i++)
Chương 2- Lớp và đối tượng 31
s.Push(i);
Vì vậy, ta không có sự an toàn dữ liệu. Lớp là một
phương tiện để khắc phục nhược điểm trên.
Lớp có được bằng cách thay từ khoá struct bằng từ khoá
class.
Lớp
Trong lớp mọi thành phần mặc nhiên đều là riêng tư
(private) nghĩa là thế giới bên ngoài không được phép
truy xuất. Do đó có sự an toàn dữ liệu.
class Stack
{
Item *st, *top;
int size;
Chương 2- Lớp và đối tượng 32
void Init(int sz) {st = top = new
Item[size=sz];}
void CleanUp() {if (st) delete [] st;}
bool Full() const {return (top - st >= size);}
bool Empty() const {return (top <= st);}
bool Push(Item x);
bool Pop(Item *px);
};
Lớp
Phát biểu:
s.size = 100; // Bao sai
Sẽ bị báo sai lúc biên dịch, nhờ đó tránh được những lỗi
lúc chạy chương trình (run-time error) rất khó tìm khi thực
hiện chương trình.
Chương 2- Lớp và đối tượng 33
Thuộc tính truy xuất
Tuy nhiên lớp như trên trở thành vô dụng vì các hàm
thành phần cũng trở thành private và không ai dùng
được. Điều đó được khắc phục nhờ thuộc tính truy xuất.
Thuộc tính truy xuất của một thành phần của lớp chỉ rõ
phần chương trình được phép truy xuất đến nó.
• Thuộc tính private
• Thuộc tính public
Chương 2- Lớp và đối tượng 34
Thuộc tính truy xuất
Các thành phần là nội bộ của lớp, bao gồm dữ liệu và
các hàm phục vụ nội bộ được đặt trong phần private.
Các hàm nhằm mục đích cho người sử dụng dùng được
đặt trong phần public.
Ví dụ sau minh hoạ thuộc tính truy xuất.
Chương 2- Lớp và đối tượng 35
// Stack.h
class Stack
{
Item *st, *top;
int size;
void Init(int sz) {st = top = new Item[size=sz];}
void CleanUp() {delete [] st;}
public:
Stack(int sz = 20) {Init(sz);}
Chương 2- Lớp và đối tượng 36
~Stack() {delete [] st;}
bool Full() const {return (top - st >= size);}
bool Empty() const {return (top <= st);}
bool Push(Item x);
bool Pop(Item *px);
};
Ví dụ về lớp và thuộc tính truy xuất
// Stack.cpp
#include "stack.h"
bool Stack::Push(Item x)
{
if (Full()) return false;
*top++ = x;
return true;
}
Chương 2- Lớp và đối tượng 37
bool Stack::Pop(Item *px)
{
if (Empty()) return false;
*px = *--top;
return true;
}
Ví dụ về lớp và thuộc tính truy xuất
// he16.cpp
#include "stack.h"
void XuatHe16(long n)
{
static char hTab[] = “0123456789ABCDEF”;
Stack s(8); int x;
do {
Chương 2- Lớp và đối tượng 38
s.Push(n%16);
n /= 16;
} while(n);
while(s.Pop(&x))
cout << hTab[x];
}
Sử dụng phạm vi truy xuất
Phạm vi truy xuất được sử dụng đúng sẽ cho phép ta kết
luận: Nhìn vào lớp thấy được mọi thao tác trên lớp.
Người dùng bình thường có thể khai thác hết các chức
năng (public) của lớp.
Người dùng cao cấp có thể thay đổi chi tiết cài đặt, cải
tiến giải thuật các hàm thành phần.
Chương 2- Lớp và đối tượng 39
Tự tham chiếu
Là tham số ngầm định của hàm thành phần trỏ đến đối
tượng. Nhờ đó hàm thành phần biết được nó đang thao
tác trên đối tượng nào.
Khi một đối tượng gọi một thao tác, địa chỉ của đối tượng
được gởi đi một cách ngầm định với tên this, tên các
thành phần của đối tượng được hiểu là của đối tượng có
địa chỉ this này.
Chương 2- Lớp và đối tượng 40
bool Stack::Push(Item x)
{
if (Full()) // if (this->Full())
return false;
*top++ = x; // this->top++ = x;
return true;
}
Phương thức thiết lập và hủy bỏ.
Phương thức thiết lập và huỷ bỏ được xây dựng nhằm
mục đích khắc phục lỗi quên khởi động đối tượng hoặc
khởi động dư. Việc quên khởi động đối tượng thường
gây ra những lỗi rất khó tìm.
Phương thức thiết lập là hàm thành phần đặc biệt được
tự động gọi đến mỗi khi một đối tượng thuộc lớp được
tạo ra. Người ta thường lợi dụng đặc tính trên để khởi
Chương 2- Lớp và đối tượng 41
động đối tượng.
Phương thức thiết lập có tên trùng với tên lớp để phân
biệt nó với các hàm thành phần khác.
Phương thức thiết lập và hủy bỏ.
Có thể có nhiều phiên bản khác nhau của phương thức
thiết lập
Phương thức huỷ bỏ là hàm thành phần đặc biệt được tự
động gọi đến mỗi khi một đối tượng bị huỷ đi. Người ta
thường lợi dụng đặc tính trên để dọn dẹp đối tượng.
Phương thức huỷ bỏ bắt đầu bằng dấu ngã (~) theo sau
bởi tên lớp để phân biệt nó với các hàm thành phần
Chương 2- Lớp và đối tượng 42
khác.
Chỉ có thể có tối đa một phương thức hb.
Phương thức thiết lập và hủy bỏ.
typedef int Item;
class Stack
{
Item *st, *top;
int size;
void Init(int sz);
void CleanUp() {delete [] st;}
public:
Stack(int sz = 20) {Init(sz);}
Chương 2- Lớp và đối tượng 43
~Stack() {CleanUp();}
bool Full() const {return (top - st >= size);}
bool Empty() const {return (top <= st);}
bool Push(Item x);
bool Pop(Item *px);
};
Hàm bạn (friends)
Nguyên tắc chung khi thao tác trên lớp là thông qua các
hàm thành phần. Tuy nhiên có những trường hợp ngoại
lệ, khi hàm phải thao tác trên hai lớp.
Hàm bạn của một lớp là hàm được khai báo ở bên
ngoài nhưng được phép truy xuất các thành phần riêng
tư của lớp.
Ta làm một hàm trở thành hàm bạn của lớp bằng cách
Chương 2- Lớp và đối tượng 44
đưa khai báo của hàm đó vào trong lớp, thêm từ khoá
friend ở đầu.
Ta dùng hàm bạn trong trường hợp hàm phải là hàm
toàn cục nhưng có liên quan mật thiết với lớp, hoặc là
hàm thành phần của một lớp khác.
Hàm thành phần hằng
Hàm thành phần hằng là hàm thành phần có thể áp
dụng được cho các đối tượng hằng.
Ta qui định một hàm thành phần là hằng bằng cách
thêm từ khoá const vào cuối khai báo của nó.
Ta khai báo hàm thành phần là hằng khi nó không thay
đổi các thành phần dữ liệu của đối tượng.
Chương 2- Lớp và đối tượng 45
Hàm thành phần hằng
inline char *strdup(const char *s)
{
return strcpy(new char[strlen(s) + 1], s);
}
class string
{
char *p;
Chương 2- Lớp và đối tượng 46
public:
string(char *s = "") {p = strdup(s);}
~string() {delete [] p;}
string(const string &s2) {p = strdup(s2.p);}
void Output() const {cout << p;}
void ToLower() {strlwr(p);}
};
Hàm thành phần hằng
void main()
{
const string Truong("DH BC TDT");
string s("ABCdef");
s.Output();
s.ToLower();
s.Output();
Chương 2- Lớp và đối tượng 47
Truong.Output();
Truong.ToLower(); // Bao loi
}
Thành phần tĩnh (static members)
Thành phần dữ liệu tĩnh là thành phần dữ liệu dùng
chung cho mọi đối tượng thuộc lớp.
Hàm thành phần tĩnh là hàm thành phần có thể hoạt
động không cần dữ liệu của đối tượng, nói cách khác,
nó không cần đối tượng.
Ta dùng hàm thàn