Trước khi bàn về OO là DP thì chị Rồng cho mình nói sơ qua Abstract Data Type (ADT) nhé.
ADT là 1 module chung để tập hợp các variables và functions có liên quan đến nhau.
Ví dụ File có các variables: name chỉ tên file, path chỉ đường dẫn tuyệt đối (absolute path), lastModifed: thời gian chỉnh sửa cuối cùng,… và các functions liên quan: open(), append(), close(),…
Trong các ngôn ngữ hỗ trợ OOP thì có dễ dàng biểu diễn dưới dạng syntax của nó, mình mô phỏng trên C# cho chị Rồng, ngắn gọn thôi, cái này chắc ai cũng làm được
public class File
{
public string Name { get; set; }
public string Path { get; set; }
public DateTime LastModifiedTime { get; }
public DateTime CreationTime { get; }
public string Owner { get; }
public boolean Open(int mode) {}
public boolea Close() {}
public int Read() {}
public int Write() {}
public int Append() {}
public boolean ChangeFileName(string newFileName) {}
public boolean Move(string path) {}
}
Tuy nhiên, C không hỗ trợ các cú pháp như class ClassName
, nên không thể chuyển sang ADT thành class như các OOP language hỗ trợ. Vì vậy có 3 cách giải quyết, có thể xem là Design Pattern để chuyển ADT thành 1 fake object trong C.
Điểm bất lợi hơn trong C là phải tự quản lý object tạo, xoá, vòng đời hoàn toàn bằng tay. Còn các ngôn ngữ OOP như C++ có RAII, Java và C# có garbage collector quản lý cho mình.
Cách 1: sử dụng 1 số nguyên hoặc con trỏ đại diện, thường là pointer hay int thông thường (giống primary key trong database).
Thường định nghĩa 1 struct có tên là struct_name
, object có kiểu là struct_name
là struct_name *
, và các functions liên quan đặt theo dạng struct_name_method_name(struct_object, ...)
Trong ví dụ biến đại diện object có kiểu FILE, là pointer tới file_description
struct file_description
{
char name[256];
char *path;
time_t last_modified_time;
time_t creation_time;
char owner[256];
};
typedef struct file_descriptor* FILE;
bool file_open(FILE file, int mode) {}
bool file_close(FILE file) {}
int file_read(FILE file) {}
int file_write(FILE file) {}
int file_append(FILE file) {}
bool file_change_file_name(FILE file, char *new_path) {}
bool file_move(FILE file, char* new_path) {}
Cách 2: sử dụng data trực tiếp, không có số nguyên nào đại diện.
struct file_description { ... };
// typedef struct file_description { ... };
bool file_open(struct file_description file, int mode);
bool file_close(struct file_description file);
...
Cách 3: sử dụng implicit global variable, thường sử dụng trong low-level graphics API
Thường có 1 function tạo implicit variable, kèm theo 1 hàm dọn dẹp implicit variable
get_current_graphics_context();
graphics_move_to(200, 200):
graphics_line_to(200, 300);
graphics_move_to(400, 400);
graphics_line_to(300, 400);
close_current_graphics_context();
Cách này có thể mở rộng bằng cách quản lý thêm 1 global stack chứa các implicit variables
void draw()
{
get_current_graphics_context();
graphics_set_stroke_color(0, 0, 0, 255); /* set black color */
graphics_move_to(200, 200):
graphics_line_to(200, 300);
graphics_context_push_stack();
graphics_set_stroke_color(255, 0, 0, 255); /* set red color */
graphics_move_to(400, 400);
graphics_line_to(300, 400);
graphics_context_pop_stack();
close_current_graphics_context();
}
Đó là 3 cách mình thường dùng để hiện thực OO trong C, chị Rồng có thể xem là trick hay Design Pattern cũng được
Cái này chỉ mới định nghĩa theo class thông thường thôi. Còn inheritance và polymorphism nữa mà mình mỏi tay quá
Chúc chị Rồng thi tốt nha