1) Lập trình hướng đối tượng là gì?
Người ta nói rằng đã là developer thì sớm muộn cũng phải đụng đến lập trình hướng đối tượng.
Lập trình hướng đối tượng là mô hình lập trình phổ biến nhất và được coi cách viết code tiêu chuẩn cho hầu hết các lập trình viên.
Lập trình hướng đối tượng hiện nay được sử dụng trong rất nhiều ngôn ngữ lập trình: Typescript, Dart, Python, Java, Ruby,...
Vậy Lập trình hướng đối tượng có gì đặc biệt, hãy cùng bắt đầu với khái niệm nhé.
Lập trình hướng đối tượng (hay OOP) là một mô hình lập trình dựa trên khái niệm về Class và Object.
Nó được sử dụng để tách một chương trình phần mềm thành các phần đơn giản, có thể tái sử dụng.
Có nhiều ngôn ngữ lập trình hướng đối tượng như C ++, Java, Python,..
2) Các khái niệm cơ bản
Các khái niệm cơ bản trong OOP bao gồm:
- Class
- Object
- Đóng gói (Encapsulation)
- Kế thừa (Inheritance)
- Đa hình (Polymorphism)
- Trừu tượng (Abstraction)
Hiểu được 6 khái niệm này (kết hợp với thực hành) nghĩa là bạn đã nắm được cơ bản của lập trình hướng đối tượng.
Trong các ví dụ bên dưới, tôi sử dụng ngôn ngữ Java.
2.1) Class
Ta hiểu Class là một kiểu dữ liệu do người dùng định nghĩa. Trong Class có các thuộc tính (attribute) và phương thức (method)
public class Nguoi {
// THUỘC TÍNH:
String hoVaTen; // họ và tên
int tuoi; // tuổi
String gioiTinh; // giới tính
String diaChi; // địa chỉ
boolean giau; // có giàu không
// PHƯƠNG THỨC:
void an() {
// code
//
}
void ngu() {
// ...
}
void xemTV() {
// ...
}
}
2.2) Object
Nếu Class là một khuôn mẫu thì Object chính là thể hiện của khuôn mẫu đó.
Từ class Nguoi
bên trên, làm sao ta tạo ra một anh bạn Will Smith, 20 tuổi, nhà giàu?
Nguoi nguoi1 = new Nguoi(); // khởi tạo Object
nguoi1.hoVaTen = "Will Smith"; // set giá trị cho thuộc tính hoVaTen
nguoi1.tuoi = 20; // set giá trị ...
nguoi1.gioiTinh = "Nam"; // ...
nguoi1.diaChi = "Mĩ";
nguoi1.giau = true;
Để dễ nhớ, tôi thường coi Class là một bản vẽ của ngôi nhà, còn Object là những ngôi nhà cụ thể, được xây thực sự.
2.3) Đóng gói
Một trong những điểm đáng chú ý về tính đóng gói đó là các thuộc tính sẽ có thuộc tính phạm vi (hay access modifier) là private
và ta cần tạo getter, setter cho các thuộc tính đó:
public class Nguoi {
private String hoVaTen;
private int tuoi;
private String gioiTinh;
private String diaChi;
private boolean giau;
public String getHoVaTen() {
return hoVaTen;
}
public void setHoVaTen(String hoVaTen) {
this.hoVaTen = hoVaTen;
}
public int getTuoi() {
return tuoi;
}
public void setTuoi(int tuoi) {
this.tuoi = tuoi;
}
public String getGioiTinh() {
return gioiTinh;
}
public void setGioiTinh(String gioiTinh) {
this.gioiTinh = gioiTinh;
}
public String getDiaChi() {
return diaChi;
}
public void setDiaChi(String diaChi) {
this.diaChi = diaChi;
}
public boolean isGiau() {
return giau;
}
public void setGiau(boolean giau) {
this.giau = giau;
}
// CÁC PHƯƠNG THỨC ...
}
Setter dùng để set giá trị cho thuộc tính, getter dùng để lấy ra giá trị của thuộc tính.
Vì vậy khi gán giá trị cho các thuộc tính của Object, code có sự thay đổi:
Nguoi nguoi1 = new Nguoi(); // khởi tạo Object
nguoi1.hoVaTen = "Will Smith"; // sẽ báo lỗi vì không thể truy cập thuộc tính private
nguoi1.setHoVaTen("Will Smith"); // không lỗi
Các từ khoá private, protected, public được gọi là các access modifier. Thường thì với thuộc tính ta sẽ để access modifier là
private
, còn với phương thức sẽ đểpublic
.
2.4) Kế thừa
Giống như cha có cái gì thì con có cái đó, kế thừa giúp class con có được những thuộc tính, phương thức của class cha.
public class LapTrinhVien extends Nguoi {
private String chucVu; // chức vụ
private float luong; // lương hàng tháng
private boolean biTri; // bị trĩ hay chưa
// getter, setter ...
}
Lúc này, các thuộc tính trong Class Nguoi
phải thay đổi access modifier từ private
sang protected
thì Class LapTrinhVien
mới được thừa hưởng các thuộc tính đó:
public class Nguoi {
protected String hoVaTen;
protected int tuoi;
protected String gioiTinh;
protected String diaChi;
protected boolean giau;
// getter, setter, ...
}
Lúc này, Class LapTrinhVien
sẽ có dạng:
public class LapTrinhVien extends Nguoi {
protected String hoVaTen;
protected int tuoi;
protected String gioiTinh;
protected String diaChi;
protected boolean giau;
private String chucVu; // chức vụ
private float luong; // lương hàng tháng
private boolean biTri; // bị trĩ hay chưa
// các phương thức từ class Nguoi ...
// getter, setter ...
}
Nói chung là class cha có thuộc tính và phương thức gì, thì class con có cái đấy.
2.5) Đa hình
Chó, mèo, vịt đều có phương thức kêu
, nhưng mèo kêu "meo meo", chó kêu "gâu gâu", vịt kêu "quạc quạc".
Một hành động được thực hiện theo những cách khác nhau tuỳ vào hoàn cảnh, đó gọi là Đa hình.
Ta có thể đạt được đa hình theo kiểu ghi đè phương thức (Method Overriding), hoặc nạp chồng phương thức (Method Overloading).
Sau đây là ví dụ về ghi đè phương thức:
class DongVat{
public void keu() {
System.out.println("Kêu");
}
}
class Cho extends DongVat {
@Override
public void keu() {
System.out.println("Gâu gâu");
}
}
class Meo extends DongVat {
@Override
public void keu() {
System.out.println("Meo meo");
}
}
class Vit extends DongVat {
@Override
public void keu() {
System.out.println("Quạc quạc");
}
}
Còn đây là ví dụ về nạp chồng phương thức:
class Nguoi {
public void chao() {
System.out.println("Xin chào");
}
public void chao(String hoTen) {
System.out.println("Xin chào, " + hoTen);
}
public void chao(String hoTen1, String hoTen2) {
System.out.println("Xin chào, " + hoTen1 + " va " + hoTen2);
}
}
Và khi gọi Object, ta có thể gọi 3 phương thức cùng tên với các loại tham số khác nhau, và kết quả cũng khác nhau:
Nguoi nguoi = new Nguoi();
nguoi.chao();
nguoi.chao("Will Smith");
nguoi.chao("Will Smith", "Chris Rock");
Kết quả:
2.6) Trừu tượng
Ta có thể lấy ví dụ về tính trừu tượng như sau: khi bạn dùng điều khiển TV, bạn chỉ cần biết bấm nút thì nó sẽ chuyển kênh cho bạn chứ bạn không cần phải hiểu đằng sau chiếc điều khiển đó những gì xảy ra.
Một ví dụ khác, với chiếc xe ô tô, khi bạn nhấn phanh, bạn chỉ cần biết là khi nhấn phanh thì xe sẽ dừng chứ bạn không cần quan tâm nguyên lý hoạt động đằng sau tính năng phanh đó ra sao.
Nói cách khác, ta chỉ quan tâm đến "What it does" chứ không cần quan tâm "How it does".
Trong Java, ta có thể đạt được Trừu tượng theo 2 cách: abstract class
và interface
.
Với abstract class
, các phương thức sẽ không có phần thân, mà chỉ có phần khai báo. Những class nào kế thừa từ nó sẽ triển khai phần thân của phương thức.
abstract class Vehicle{
abstract void start () ;
abstract void stop ();
abstract void accelerate ();
abstract void brake ();
}
class Car extends Vehicle{
void start () { //code here…}
void stop () { //code here…}
void accelerate () { //code here…}
void brake () {
System.out.println("Car braked");
}
}
class Bike extends Vehicle{
void start () { //code here…}
void stop () { //code here…}
void accelerate () { //code here…}
void brake () { //code here…}
}
class Scooter extends Vehicle{
void start () { //code here…}
void stop () { //code here…}
void accelerate () { //code here…}
void brake () { //code here…}
}
Khi sử dụng, ta có thể khởi tạo Object dạng như sau:
Vehicle car = new Car();
car.brake();
Kết quả:
Class Bike
và Scooter
cũng có thể làm tương tự.
2.7) Một số khái niệm khác
- Constructor
- Interface
- Toán tử this
- Toán tử super
- Thuộc tính phạm vi
- Quan hệ IS-A
- Quan hệ HAS-A
3) Kết
Hi vọng bài viết đã giúp bạn có được cái nhìn tổng quan và những khái niệm cơ bản của lập trình hướng đối tượng.
Với những bạn mới học lập trình hướng đối tượng, lời khuyên của tôi là không cần đọc quá nhiều lý thuyết, hãy code thật nhiều. Sau đó quay lại với các khái niệm, bạn sẽ vỡ ra nhiều thứ hơn, hiểu sâu hơn.
Lập trình hướng đối tượng hiện nay được dùng rất nhiều trong các công nghệ và ngôn ngữ lập trình: Angular sử dụng Typescript, Flutter sử dụng Dart, Python, Java ,... Vì vậy rất đáng để bạn đầu từ thời gian và công sức.