Đóng gói và khả năng mở rộng của kiểu
OOP là một cách tiếp cận cân bằng để viết phần mềm. Dữ liệu và hành vi được đóng gói cùng nhau. Sự đóng gói này tạo ra các kiểu dữ liệu do người dùng định nghĩa, mở rộng các kiểu dữ liệu của ngôn ngữ và tương tác với chúng. Khả năng mở rộng kiểu là cơ hội để thêm vào ngôn ngữ các kiểu dữ liệu do người dùng định nghĩa, dễ sử dụng như các kiểu cơ bản.
Một kiểu dữ liệu trừu tượng, ví dụ như chuỗi, là mô tả về một kiểu hành vi lý tưởng, quen thuộc.
Người dùng chuỗi biết rằng các thao tác chuỗi, như nối hoặc in, có một hành vi nhất định. Các thao tác nối và in được gọi là phương thức.
Một triển khai cụ thể của ADT có thể có một số hạn chế, ví dụ, chuỗi có thể bị giới hạn độ dài. Những hạn chế này ảnh hưởng đến hành vi được mở cho tất cả. Đồng thời, các chi tiết triển khai nội bộ hoặc riêng tư không ảnh hưởng trực tiếp đến cách người dùng nhìn nhận đối tượng. Ví dụ, chuỗi thường được triển khai dưới dạng mảng, trong khi địa chỉ cơ sở nội bộ của mảng này và tên của nó không quan trọng với người dùng.
Đóng gói là khả năng ẩn chi tiết triển khai khi cung cấp các giao diện mở cho kiểu do người dùng định nghĩa. Trong MQL5, cũng như trong C++, định nghĩa lớp và cấu trúc (class và struct) được sử dụng để cung cấp đóng gói kết hợp với các từ khóa truy cập private
, protected
và public
.
Từ khóa public
cho thấy rằng quyền truy cập vào các thành viên đứng sau nó là không bị hạn chế. Nếu không có từ khóa này, các thành viên lớp mặc định bị khóa. Các thành viên riêng chỉ có thể được truy cập bởi các hàm thành viên của chính lớp đó.
Các hàm lớp được bảo vệ có thể truy cập được bởi các hàm lớp không chỉ trong lớp của nó mà còn trong các lớp kế thừa từ nó. Các hàm lớp công khai có thể truy cập bởi bất kỳ hàm nào trong phạm vi khai báo lớp. Sự bảo vệ cho phép ẩn một phần triển khai của lớp, từ đó ngăn chặn các thay đổi không mong muốn trong cấu trúc dữ liệu. Hạn chế truy cập hoặc ẩn dữ liệu là một đặc trưng của lập trình hướng đối tượng.
Thông thường, các hàm lớp được bảo vệ và khai báo với bộ sửa đổi protected
, việc đọc và ghi giá trị được thực hiện bằng cách sử dụng các phương thức đặc biệt gọi là set và get, được định nghĩa bởi bộ sửa đổi truy cập public
.
Ví dụ:
class CPerson
{
protected:
string m_name; // tên
public:
void SetName(string n){m_name=n;} // đặt tên
string GetName(){return(m_name);} // trả về tên
};
2
3
4
5
6
7
8
Cách tiếp cận này mang lại một số lợi ích. Thứ nhất, qua tên hàm, chúng ta có thể hiểu nó làm gì - đặt hoặc lấy giá trị của một thành viên lớp. Thứ hai, có thể trong tương lai chúng ta sẽ cần thay đổi kiểu của biến m_name trong lớp CPerson hoặc trong bất kỳ lớp dẫn xuất nào của nó.
Trong trường hợp này, chúng ta chỉ cần thay đổi triển khai của các hàm SetName() và GetName(), trong khi các đối tượng của lớp CPerson vẫn có thể được sử dụng trong chương trình mà không cần thay đổi mã vì người dùng thậm chí sẽ không biết rằng kiểu dữ liệu của m_name đã thay đổi.
Ví dụ:
struct Name
{
string first_name; // tên
string last_name; // họ
};
class CPerson
{
protected:
Name m_name; // tên
public:
void SetName(string n);
string GetName(){return(m_name.first_name+" "+m_name.last_name);}
private:
string GetFirstName(string full_name);
string GetLastName(string full_name);
};
void CPerson::SetName(string n)
{
m_name.first_name=GetFirstName(n);
m_name.last_name=GetLastName(n);
}
string CPerson::GetFirstName(string full_name)
{
int pos=StringFind(full_name," ");
if(pos>0) StringSetCharacter(full_name,pos,0);
return(full_name);
}
string CPerson::GetLastName(string full_name)
{
string ret_string;
int pos=StringFind(full_name," ");
if(pos>0) ret_string=StringSubstr(full_name,pos+1);
else ret_string=full_name;
return(ret_string);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Xem thêm