Giải pháp chuyển đổi số trọn gói cho doanh nghiệp Việt

Tổng Quan Lập Trình Hướng Đối Tượng - Lập trình Java

Lập trình Java

← Toàn bộ tài liệu


Bài 15: Tổng Quan Lập Trình Hướng Đối Tượng

Bài 15/56 Xem dạng sách

Các Hướng Tư Duy Trong Lập Trình

Lập trình hướng-đối-tượng hay hướng-cái-gì đi nữa thì cũng chỉ là một giải pháp, một tư duy trong lập trình mà thôi. Nó không cao siêu hay phức tạp gì. Nó cũng không phụ thuộc vào ngôn ngữ lập trình Java hay gì cả. Nó chỉ là tập hợp các phương pháp và nguyên tắc để giúp bạn suy nghĩ và tổ chức vấn đề, từ đó giúp làm ra một chương trình phức tạp và to lớn một cách dễ dàng hơn.

Và dĩ nhiên với việc suy nghĩ theo một hướng lập trình nào đó, thì ngôn ngữ lập trình cũng phải hỗ trợ lập trình viên các cú pháp theo các nguyên tắc hướng đó. Chính vì vậy chúng ta mới có các ngôn ngữ lập trình hướng đối tượng hay không hướng đối tượng. Như ngôn ngữ Java mà các bạn đang tìm hiểu là một ngôn ngữ hướng đối tượng.

Có thể nói là có rất nhiều tài liệu đã mô tả cụ thể về thế nào là lập trình theo hướng đối tượng và thế nào là lập trình không hướng đối tượng. Nhưng với một vài tài liệu mà mình biết, chắc chắn là rất khó để các bạn hiểu sự khác nhau này. Vậy với các bài học của mình thì mình mời các bạn tiếp cận các hướng lập trình theo một cách hoàn toàn khác, đó là, chúng ta hãy cùng xem qua một ví dụ đơn giản, và cùng nhau thay đổi tư duy dần dần để từng bước khám phá cách thức xây dựng một ứng dụng theo hướng cũ và hướng đối tượng sẽ ra sao nhé.

Xây Dựng Ứng Dụng Theo Hướng “Cũ”

Giả sử có yêu cầu rằng bạn hãy viết một chương trình kêu người dùng nhập vào Bán kính của một Hình tròn, sau đó chương trình sẽ in ra console Chu vi và Diện tích của Hình tròn đó.

Nếu bạn bắt tay vào code nhanh sườn của chương trình, thì nó sẽ trông như thế này.

public static void main(String[] args) {
// Kêu người dùng nhập vào Bán kính Hình tròn
System.out.print("Hãy nhập vào Bán kính Hình tròn: ");
Scanner scanner = new Scanner(System.in);
float r = scanner.nextFloat();
 
// Tính Chu vi Hình tròn ở đây
// ...
 
// Tính Diện tích Hình tròn ở đây
// ...
 
// Xuất kết quả Chu vi và Diện tích của Hình tròn ra console
System.out.println("Chu vi Hình tròn: ");
System.out.println("Diện tích Hình tròn: ");
}

Với cách tiếp cận từ Bài học số 1 đến giờ, rất dễ để bạn bắt tay vào hoàn thành chương trình này đúng không nào. Để tính Chu vi và Diện tích của Hình tròn, chúng ta chỉ cần áp dụng kiến thức toán học vào mà thôi, bạn xem code hoàn chỉnh như sau.

public static void main(String[] args) {
// Khai báo số PI là hằng số
final float PI = 3.14f;
 
// Kêu người dùng nhập vào Bán kính Hình tròn
System.out.print("Hãy nhập vào Bán kính Hình tròn: ");
Scanner scanner = new Scanner(System.in);
float r = scanner.nextFloat();
 
// Tính Chu vi Hình tròn ở đây
float cv = 2*PI*r;
 
// Tính Diện tích Hình tròn ở đây
float dt = PI*r*r;
 
// Xuất kết quả Chu vi và Diện tích của Hình tròn ra console
System.out.println("Chu vi Hình tròn: " + cv);
System.out.println("Diện tích Hình tròn: " + dt);
}

Ôi có khó gì đâu! Cách tư duy như chúng ta làm với ví dụ này người ta gọi là tư duy theo hướng thủ tục (POP – Procedure Oriented Programming), hay có thể gọi là hướng cấu trúc. Bởi vì chúng ta tư duy theo kiểu chia nhỏ yêu cầu ra thành các “thủ tục”, các thủ tục ở đây là các hành động có thể có của một chương trình. Chẳng hạn như với ví dụ trên chúng ta có các thủ tục tính Chu vi Hình tròn, tính Diện tích Hình tròn. Bạn cũng có thể tách từng thủ tục này thành các phương thức (chúng ta sẽ học đến phương thức sau) cho chương trình dễ nhìn hơn kiểu như sau.

// Khai báo số PI là hằng số
static final float PI = 3.14f;
 
public static void main(String[] args) {
// Kêu người dùng nhập vào Bán kính Hình tròn
System.out.print("Hãy nhập vào Bán kính Hình tròn: ");
Scanner scanner = new Scanner(System.in);
float r = scanner.nextFloat();
 
// Chu vi Hình tròn
float cv = chuViHinhTron(r);
 
// Diện tích Hình tròn
float dt = dienTichHinhTron(r);
 
// Xuất kết quả Chu vi và Diện tích của Hình tròn ra console
System.out.println("Chu vi Hình tròn: " + cv);
System.out.println("Diện tích Hình tròn: " + dt);
}
 
public static float chuViHinhTron(float r) {
return 2 * PI * r;
}
 
public static float dienTichHinhTron(float r) {
return PI * r * r;
}

Câu chuyện chưa dừng lại ở đây. Giả sử yêu cầu được nâng tầm lên. Đòi hỏi chương trình hỗ trợ thêm các phương thức liên quan đến Hình trụ. Cụ thể là nhập thêm chiều cao Hình trụ rồi sau đó in ra thêm Thể tích Hình trụ (Hình trụ này có Bán kính mặt tròn bằng với Bán kính Hình tròn trên kia).

Vậy là với tư duy hướng thủ tục, bạn cũng sẽ kêu dễ, và… Boom! Code mới ra đời với một số thủ tục mới.

// Khai báo số PI là hằng số
static final float PI = 3.14f;
 
public static void main(String[] args) {
// Kêu người dùng nhập vào Bán kính Hình tròn
System.out.print("Hãy nhập vào Bán kính Hình tròn: ");
Scanner scanner = new Scanner(System.in);
float r = scanner.nextFloat();
 
// Kêu người dùng nhập vào Chiều cao Hình trụ
System.out.print("Hãy nhập vào Chiều cao Hình trụ: ");
float h = scanner.nextFloat();
 
// Chu vi Hình tròn
float cv = chuViHinhTron(r);
 
// Diện tích Hình tròn
float dt = dienTichHinhTron(r);
 
// Thể tích Hình trụ
float ttHinhTru = theTichHinhTru(dt, h);
 
// Xuất kết quả Chu vi và Diện tích của Hình tròn, Thể tích Hình trụ ra console
System.out.println("Chu vi Hình tròn: " + cv);
System.out.println("Diện tích Hình tròn: " + dt);
System.out.println("Thể tích Hình trụ: " + ttHinhTru);
}
 
public static float chuViHinhTron(float r) {
return 2 * PI * r;
}
 
public static float dienTichHinhTron(float r) {
return PI * r * r;
}
 
public static float theTichHinhTru(float dt, float h) {
return dt * h;
}

Cũng may là các hàm tính Chu vi, Diện tích, Thể tích trong ví dụ này rất ngắn. Nhưng bạn có thể thấy nếu yêu cầu ngày một phát sinh, như đòi hỏi tính thêm Chu vi hay Diện tích hay Thể tích cho các Hình vuông, Hình bình hành, Hình cầu,… thì các thủ tục trong chương trình của bạn sẽ phình ra đến mức nào, làm cho chương trình càng khó quản lý nữa. Do đó cần phải có một kiểu tư duy mới khiến cho việc quản lý code được dễ dàng hơn, thậm chí có thể rút ngắn thời gian code thông qua việc tận dụng lại các thủ tục tính toán nữa. Vậy là từ mong muốn đó, tư duy hướng đối tượng ra đời.

Có nhiều tài liệu cho rằng, phương thức suy nghĩ theo tư duy hướng thủ tục này là tư duy kiểu top-down, tức là theo kiểu từ trên-xuống, hay còn có thể hiểu là tư duy theo kiểu tổng quát đến cụ thể. Vậy là sao? Tức là bạn sẽ nhìn tổng thể yêu cầu của chương trình trước, như ví dụ bạn thấy ngay yêu cầu là tính Chu vi và Diện tích hình tròn, bạn sẽ xây dựng các thủ tục tính toán đó trước. Sau khi tiếp cận cái tổng thể đó, thì bạn thấy cần phải viết thêm các thủ tục nhỏ hơn để mà dễ quản lý, chẳng hạn bạn muốn thêm các thủ tục tính Bình phương, Thập phương của một số hạng. Nếu còn có thể phân chia thủ tục nhỏ đó thành các thủ tục nhỏ hơn nữa thì cứ phân chia. Đó chính là tư duy kiểu top-down.

Xây Dựng Ứng Dụng Theo Hướng Đối Tượng

Hướng đối tượng (OOP – Object Oriented Programming). Cách tư duy mới này sẽ không hướng đến các thủ tục nữa, mà là hướng đến các đối tượng. Ngoài thực tế thì các đối tượng sẽ là các thực thể hay sự vật mà chúng ta có thể cầm nắm, có thể gọi tên được, và còn có cả trạng thái và hành vi. Áp dụng vào trong chương trình phần mềm thì khái niệm đối tượng vẫn y như vậy.

Chẳng hạn với ví dụ viết chương trình tính Chu vi và Diện tích Hình tròn trên đây. Thì đối tượng mà ta cần quan tâm đó chính là Hình tròn. Vậy làm sao để giải quyết yêu cầu? Như bạn đã biết, đối tượng được sinh ra trong lập trình (hay ngoài đời thực) đều có những trạng thái (đặc điểm) và hành vi (hành động) nhất định. Như ở đây Hình tròn có đặc điểm là độ lớn của nó, chính là giá trị Bán kính, còn hành động của nó chính là các phép tính Chu vi và Diện tích của bản thân mình. Thậm chí bạn có thể xây dựng cho Hình tròn tự nó phải có trách nhiệm kêu người dùng nhập vào Bán kính và lưu lại. Rồi trách nhiệm tự nó in kết quả Chu vi và Diện tích ra console luôn. Khỏe!!! Như mình minh họa bằng code dưới đây, bạn không cần phải biết chính xác code này là như nào đâu, chỉ cần biết ý tưởng của hướng đối tượng như thế nào là được.

public static void main(String[] args) {
// Khai báo Đối tượng Hình tròn và ra lệnh cho đối tượng này thực hiện
// các yêu cầu
HinhTron hinhTron = new HinhTron();
 
// Hình tròn tự kêu người dùng nhập Bán kính
hinhTron.nhapBanKinh();
 
// Hình tròn tự nó biết cách tính Chu vi
hinhTron.tinhChuVi();
 
// Hình tròn tự nó biết cách tính Diện tích
hinhTron.tinhDienTich();
 
// Hình tròn tự in kết quả ra console
hinhTron.inChuVi();
hinhTron.inDienTich();
}

Bạn có nhận ra sự gọn gàng và dễ quản lý trong code không? Mình rất thích nhìn thấy code như thế này.

Khác biệt sẽ rất lớn khi mà các thủ tục tính Chu vi, tính Diện tích là các thủ tục lớn và phức tạp. Khi đó các thủ tục của Đối tượng nào sẽ được giao cho Đối tượng đó, tức là bạn xây dựng các thủ tục đặc thù đó bên trong các Đối tượng (bạn sẽ được biết cách xây dựng này sau), và khi cần đến các thủ tục nào, chúng ta chỉ cần gọi đến thủ tục thông qua đối tượng đã được khai báo, như đối tượng HinhTron trên đây.

Với việc bạn chỉ định Hình tròn phải có các thủ tục của nó. Thì việc thêm vào một Hình trụ cũng chỉ là việc khai báo thêm một đối tượng mới, với các thủ tục mới tương xứng. Ngoài ra thì đối tượng Hình trụ còn có các đặc tính và thủ tục giống như Hình tròn, do đó chúng ta hoàn toàn có thể dùng lại được các thủ tục đã khai báo bên Hình tròn. Người ta gọi việc dùng lại các thủ tục này là tính kế thừa trong hướng đối tượng, thông qua việc chỉ định Hình trụ là con của Hình tròn (chúng ta sẽ xem xét mối quan hệ kế thừa này ở các bài học sau). Việc Hình trụ là con Hình tròn khiến nó có được các trạng thái và hành vi mà cha nó là Hình tròn đã định nghĩa, nên việc quản lý và sử dụng lại code rất dễ dàng. Về sau nếu như xuất hiện thêm Hình cầu, Hình abc, hay Hình xyz gì đó, thì chúng ta hoàn toàn có thể tạo các đối tượng và chúng sẽ có mối quan hệ nào đó với nhau, kèm các thủ tục đặc trưng hay kế thừa của nhau.

Mình cũng ví dụ bằng code cho mong muốn được tính Thể tích Hình trụ như sau.

public static void main(String[] args) {
// Khai báo Đối tượng Hình trụ
// Và ra lệnh cho đối tượng này thực hiện
// các yêu cầu
HinhTru hinhTru = new HinhTru();
 
// Hình trụ tự kêu người dùng nhập Bán kính
// Thực chất bên trong thủ tục này Hình trụ gọi đến
// phương thức nhập bán kính
// mà cha của nó là Hình tròn đã khai báo
hinhTru.nhapBanKinh();
 
// Hình trụ tự kêu người dùng nhập Chiều cao
hinhTru.nhapChieuCao();
 
// Hình trụ tự nó biết cách tính Chu vi
// Cũng dùng đến phương thức
// tính Chu vi mà cha nó là
// HinhTron đã khai báo
hinhTru.tinhChuVi();
 
// Hình trụ tự nó biết cách tính Diện tích
// Cũng dùng đến phương thức
// tính Diện tích mà cha nó là
// Hình tròn đã khai báo
hinhTru.tinhDienTich();
 
// Hình trụ tự nó biết cách tính Thể tích
hinhTru.tinhTheTich();
 
// Hình trụ tự in kết quả ra console
hinhTru.inChuVi(); // Có gọi đến phương thức in kết quả của cha nó là Hình tròn
hinhTru.inDienTich(); // Có gọi đến phương thức in kết quả của cha nó là Hình tròn
hinhTru.inTheTich();
}

Nếu hướng thủ tục trên kia là tư duy theo kiểu top-bottom. Thì việc hướng đối tượng này, với tiếp cận đầu tiên đến từng đối tượng như Hình tròn, Hình trụ như ví dụ trên, sau đó ta mới xây dựng các thủ tục cho nó, thêm các mối quan hệ, chỉnh sửa các vai trò cho từng đối tượng khi mà yêu cầu hệ thống càng ngày càng phức tạp. Cách suy nghĩ này người ta gọi là tư duy kiểu bottom-up, tức là theo kiểu từ dưới lên, hay còn có thể hiểu là từ cụ thể đến tổng quát.

Vậy thôi! Tư duy theo hướng đối tượng cốt lõi là thế thôi. Bạn đã thấy thích lập trình theo hướng đối tượng rồi đúng không nào. Không thích cũng phải thích nhé, vì nếu không có hướng đối tượng, thì các ứng dụng lớn sau này bạn không thể xây dựng nổi đâu. Trên đây chỉ là ví dụ vắn tắt về hướng đối tượng thôi, mọi thứ râu ria và thế mạnh của nó chúng ta sẽ dần dần nói đến ở các bài học sau nữa nhé.

Vậy Tóm Lại, Tư Duy Theo Hướng Đối Tượng Là Như Thế Nào?

Như bạn đã làm quen trên đây, mục này mình chốt lại thôi. Đó là, đã gọi là hướng đối tượng, tức là mong muốn bạn luôn suy nghĩ mọi thứ theo đối tượng.

Chẳng hạn với yêu cầu xây dựng phần mềm quản lý Sinh viên, thì Trường học, Lớp học, Sinh viên, Giáo viên, thậm chí Bàn ghế, Máy chiếu, Môn học,… đều có thể trở thành đối tượng để chúng ta vận dụng trong việc quản lý. Miễn là đối tượng đó có xuất hiện bên trong ứng dụng của chúng ta.

Hay với yêu cầu xây dựng phần mềm quản lý Tour (như TourNote bên bài học Android), thì Ghi chú, Chủ đề, Tài khoản, Hành trình,… đều là các đối tượng mà bạn có thể tổ chức.

Sơ đồ quan hệ các bảng

Table Name: {{table.name}}
Num Name Type
{{field_index+1}}
{{field.name}} {{field.type}}

Hỏi đáp

Gửi với tên {{comment_full_name}}

Chưa có câu hỏi nào cho bài này.

Zalo 0936.006.058 Hotline 0936.006.058