Xin demo app sử dụng OOP

Chuyện là mình làm về Embedded - Lập trình Nhúng. Công việc của mình chủ yếu dùng C nên việc dùng và vấp với thực tế về OOP còn rất kém. Gần đây mình bắt đầu thấy cần thiết áp dụng tư duy phân rã đối tượng của OOP vào công việc. Mình muốn xin ae một vài source code về cách ae dùng mấy tính chất của OOP trong thực tế khi ae làm một số app demo.
Đặc biêt, về 2 tính chất: Đa hình và Trừ tượng hóa.
Trước giờ mình cũng có code C++, Java nhưng chỉ ở mức hiểu định nghĩa tính chất và dùng Kế Thừa và Tính đóng gói thôi chứ 2 tính chất trên ít gặp. Mong ae share và giúp đỡ.
Thanks!

Nó không hề khó nhưng cách tư duy và triển khai nó khác kiểu thủ tục của C.
Xin code bạn mà bạn chưa nắm được OOP thì đọc cũng chẳng hiểu gì đâu.

Bạn làm nhúng đã từng dùng C# ?
Nếu có thì tìm hiểu OOP của C#. Sau đó qua C++ chưa muộn

3 Likes

4 tính chất OOP thì mình nắm được, chỉ là chưa dùng nhiều.
Xưa cũng làm mấy bài tập trên lớp có dình tới, nhưng chỉ ở mức cơ bản.
Đa Hình và Abstraction chưa được dùng nhiều nên muốn xem 1 project implement 2 cái đó như nào, khi nào dùng.
Còn kế thừa với đóng bao thì always rồi, nên mình dùng khá tốt.

Tính trừu tượng thì nó thể hiện trong suy nghĩ và cách tư duy. Tức là suy nghĩ tìm và rút ra các điểm chung, các điểm đặc trưng để gom vào các nhóm, các lớp (class) để có thể áp dụng các thuật toán chung hoặc phục vụ cho vấn đề kế thừa.

Ví dụ code mô tả một trang trại có nhiều loài chó thỏ mèo gà… thì mình sẽ rút ra các đặc trưng chung của chúng như có thể ăn, có thể di chuyển, ngủ, … và gom chung vào 1 lớp là động vật và cho tất cả chúng kế thừa từ lớp động vật. Thế nên mấy bài vỡ lòng về OOP toàn mang động vật ra để làm mẫu :smile:

Còn đa hình.
Cái khác dễ nhất so với C là overload (nạp chồng). Tức là có thể viết nhiều hàm (phương thức) cùng tên nhưng khác nhau đối số). C không làm được điều này.
Cái thứ 2 là override (ghi đè). Sẽ xuất hiện khi sử dụng kế thừa. Mặc dù kế thừa cùng 1 nguồn gốc nhưng trong mỗi cái chung được kế thừa thì nó cũng yêu cầu khác nhau. Ví dụ cùng là cách di chuyển kế thừa từ lớp động vật nhưng chim thì bay, chó thì chạy, cá thì bơi… tức là đa hình thái.
Thì override hiểu đơn giản là che đi những cái mặc định đã có khi kế thừa bằng một cái khác để tạo ra sự khác nhau.

5 Likes

Ví dụ thế này nhé:
Bây giờ một ngày nào đó thằng PỏnHub nó gọi cho bạn, nó bảo bạn làm cho một module hoặc một app để chat.
Cái này cho phép các đồng dâm chat với nhau, các đồng dâm có thể gọi video, gọi cho pỏnStar,gửi file video hoặc ảnh,v.v…

Nếu dùng OOP bạn sẽ phân tích yêu cầu khách hàng ra một thứ gọi là các đối tượng.
theo như yêu cầu ta có thể đẻ ra một số đối tượng như Con người ( bao gồm người dùng bình thường và các pỏnStar sẽ kế thừa lớp này), ngoài ra các đối tượng khác như các Service để gửi và nhận tn, video,…, các đối tượng tầng kết nối với database,…
tức là phân tích bài toán ra các đối tượng và xem xét xem các đối tượng này liên kết với nhau thế nào.
bước này ta mới tính tới cái tiếp theo là trừu tượng hoá.
Ví dụ một số tính năng bao gồm:

  • Gửi tin nhắn
  • Nhận tin nhắn
  • Upload video, Ảnh,…

Đó, khi này bạn đâu cần quan tâm cái gửi tin nhắn kia nó hoạt dộng như nào, bạn chỉ cần tổng quát hoá nó, đưa cho nó các phương thức cần phải thực hiện, còn thực hiện thế nào thì ta đi đến tính chất Đa Hình, xong rồi bạn chỉ cần tạo các lớp trừ tượng hoặc Interface có chứa các chức năng đó.
Ngoài ra, nếu đi sâu hơn nữa, các interface hay abstract class còn có thể giúp các class bớt phụ thuộc vào nhau.(Thôi cái này đau đầu lắm, sau khi thông đống này r bạn học vẫn chưa muộn)
Khi đã có một bản thiết kế về các chức năng cần làm, lúc này ta mới implement nó

[Đa Hình]
Cùng là một method Gửi tin nhắn, nhưng ông A gửi cho chị B cái ảnh ông ý đang abcxyz, còn chị B thấy tởm quá thì gửi lại cho lão A 1 tin nhắn dạng text "Tởm vl ông êi, dừng ngay hành động mất mặt này lại đi :3 " =)) đó là khi đa hình phát huy tác dụng. Một method có thể có nhiều các xử lý khác nhau, trả về kq khác nhau,… đơn giản nhất như trong mọi ngôn ngữ lập trình, thứ bạn gặp mọi nơi mà có khi bạn đếch quan tâm … đó chính là cái thằng print(), thấy chửa? bạn truyền cái mẹ gì vào cho nó thì nó inn ra cái đấy =)) string thì in string, int thì in ra int,…

Còn đóng gói thì quá dễ, đó là việc đóng gói các tác vụ có cùng miền nghiệp vụ vào một nơi, hoặc việc bảo vệ code hay hạn chế việc truy cập các thuộc tính hay method của một class thông qua việc sử dụng access modifier, vân vân mêy mêy,… ví dụ trong java có 4 access modifier. thường những thuộc tính của một class sẽ là private, để sử dụng các thuộc tính này LTV sẽ dùng thông qua các geter, setter .

public class Person{
    private String id;
    private String name;

    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name = name;
    }
}

Sau đấy bạn gói hết đống class kiểu này vào một folder tên là Models hay Entities gì đó,…
Đó gọi là đóng gói.

Nói chung đấy mới chỉ là một góc rất nhỏ của lập trình OOP, qua thời gian tìm hiểu, làm thật nhiều các bài tập rồi bạn sẽ rút ra đc kinh nghiệm, ví dụ trên mình đưa ra cho vui thôi, nhưng thường thì một sản phẩm trong thực tế sẽ tương tự nhuư vậy. Nó xuất hiện khắp nơi, có khi bạn đang dùng nó mà bạn chả nhận ra.

4 Likes
  • đa hình = void * có kiểm tra kiểu lúc run-time (C ép kiểu vô tư ko cần check cái gì hết :V)
  • kế thừa = ko bao giờ dùng trừ phi cần đa hình. Luôn xài composition (tức là struct trong struct :V) thay cho kế thừa. Kế thừa nên là 1 phần của đa hình, ko phải 1 trong 4 tính chất của OOP.

C lão làng rồi thì 2 dòng vậy là xong OOP rồi đó :V

ví dụ như trong curl có option CURLOPT_WRITEFUNCTION gì đó, có khai báo như sau:

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WRITEFUNCTION, write_callback);

trong đó write_callback là con trỏ hàm:

size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata);

rồi sử dụng như sau: https://curl.haxx.se/libcurl/c/url2file.html

// ... tạo curl_handle, gán 1 url nào đó cho curl_handle
// gán write function là hàm `write_data`
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
// gán userdata là con trỏ `pagefile`
FILE *pagefile = fopen(pagefilename, "wb");
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);
// get html của url đó
curl_easy_perform(curl_handle);

trong đó userdata là buffer để viết data vào, ptr là data cần viết. Đây là 1 kiểu “đa hình” của C. Với userdatawrite_callback khác nhau thì output của curl có thể khác nhau. Ví dụ userdataFILE *write_callbackfwrite thì nó output ra file, còn userdatachar **write_callback là 1 hàm custom wrrite nào đó có thể cấp phát động lại cho char ** userdata thì nó output ra chuỗi chẳng hạn :V

nếu viết lại theo kiểu OOP thì chỉ đơn giản là

// tạo curl_handle, gán 1 url nào đó cho curl_handle
CurlHandle curlHandle;
curlHandle.setUrl("http://example.com");
// get html :V :V 
CurlDataReceiver fileReceiver = new FileReceiver("example.html");
curlHandle.write(fileReceiver);
// hoặc
//CurlDataReceiver stringReceiver = new StringReceiver();
//curlHandle.write(stringReceiver);

có vẻ dễ đọc hơn set writefunction + set userdata :V Trong C phải viết thêm 2 hàm write_callback cho file và write_callback cho string thì trong OOP phải viết 2 class FileReceiver và StringReceiver kế thừa từ CurlDataReceiver, quá tải hàm write nào đó :V

6 Likes

Sau khi callback dc gọi, nó sẽ check type of parameters rồi call tới function tương ứng, đúng là đa hình.

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?