Hoặc có thể vào ĐÂYđể tìm hiểu rõ hơn về principles of object oriented
Đó là theo quan điểm hàn lâm. Nói dễ hiểu hơn Object oriented programming(OOP) hay Lập trình hướng đối tượng. Được phát triển từ những năm 2000 nhằm thay thế cho lập trình thủ tục như C. Giúp người lập trình quản lý phát triển và quản lý code dễ dàng hơn.
Nhìn vào tên của nó bạn cũng có thể hình dung ra được. Ngôn ngữ lập trình này giải quyết các bài toán từ nhỏ đến lớn bằng cách quan sát và tưởng tượng những hành động, đặc điểm của thực thể thật ngoài đời sống và đem vào lập trình như một đối tượng ảo. Thể hiện qua các lớp (class), đối tượng (Object) mà hành động là các hàm(method) còn đặc điểm chính là các biến(variable)
Nói 1 cách hoa mỹ hơn
OOP is the art of observing of objects in their natural appearance and trying to capture the functional abstractnesses in descriptive programming way, and to visualize them as virtual-workable objects
OOP là nghệ thuật quan sát các đối tượng trong tự nhiên rồi cố gắng nắm bắt những hành động cùng đặc tính của chúng và biểu diễn dưới dạng đối tượng ảo trong ngôn ngữ lập trình
Ví dụ:
Xe (đời thực)-> class Xe(lập trình) -> Đối tượng Xe
Trong đó
Xe thật thì có màu, số bánh, tên xe
-> Class Xe (Biến màu, biến Số bánh. biến Tên)
-> Đối tượng xe(Màu,Số bánh, tên)
Lập trình hướng đối tượng luôn đi kèm 4 đặc điểm chính
Abstraction : tính trừu tượng.
Encapsulation : tính đóng gói.
Inheritance : tính kế thừa.
Polymorphism : tính đa hình.
Các thuộc tính của lập trình hướng đối tượng
-
Tính đóng gói (encapsulation) và che giấu thông tin (information hiding)
Trước khi tìm hiểu tính đóng gói và che giấu thông tin, các bạn nên tìm hiểu cú pháp ngôn ngữ các thể hiện tính chất public, private, protected …
Hình ảnh trên là một ví dụ về tính đóng gói và che giấu thông tin trong lập trình OOP
Như bạn thấy, viên thuốc được bao quanh bởi lớp vỏ chính là Class
Method và Variable là những thành phần bên trong viên thuốc, được bao lại, che giấu đi và không thể nhìn hoặc sử dụng nếu Class bên ngoài không cho phép.
Như vậy tính đóng gói có thể hiểu: Gói dữ liệu (data, ~ biến, trạng thái) và mã chương trình (code, ~ phương thức) thành một cục gọi là lớp (class) để dễ quản lí. Trong cục này thường data rất rối rắm, không tiện cho người không có trách nhiệm truy cập trực tiếp, nên thường ta sẽ che dấu data đi, chỉ để lòi phương thức ra ngoài
-
Tính kế thừa (inheritance) Và đa hình(Polymorphism)
Khái niệm: Kế thừa là cách tạo lớp mới từ các lớp đã được định nghĩa từ trước
Lớp cha có thể chia sẻ dữ liệu và phương thức cho các lớp con, các lớp con khỏi phải định nghĩa lại những logic chung, giúp chương trình ngắn gọn. Nếu lớp cha là interface, thì lớp con sẽ di truyền những contract trừu tượng từ lớp cha
Giả sử ta có 2 class A và B:
- Class A: lớp cơ sở (lớp cha) - supper class
- Class B: lớp dẫn xuất (lớp con) - sub class
Class B có thể dùng được hầu hết các phương thức (hàm) và các thuộc tính
(biến) của lớp A ngoại trừ các các phương thức và các hàm các tính chất private.
Cài đặt: để cài đặt lớp kế thừa ta dùng toán tử “:” (trong C++, C#) và Extends (Java). Ví dụ B kế thừa A viết là: B:A
class A
{
....
}
class B:A // hoặc B extends A (java)
{
...
}
Chú ý:
- Một lớp cha có thể có nhiều lớp con
- Đến lượt mình mỗi lớp con lại có thể có các con khác
- Trong C++ cho phép đa kế thừa (một lớp con có thể nhận hơn 1 lớp cha)
- Java chỉ cho phép mỗi lớp con kế thừa 1 và chỉ một lớp cha/ từ khóa implement sẽ thay thế cho đa kế thừa từ C++
Ví dụ: Code Java
Class nhân viên Employee có các thuộc tính name và salary
class Employee{
private String name;
private float salary;
public Employee() {
}
public Employee(String name, float salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}
//method say
public void SayHello(){
System.out.println("Xin chaof");
}
}
//class Programmer có thêm 1 thuộc tính bonus kế thừa clas Employee
public class Programmer extends Employee{
private float bonus;
public float getBonus() {
return bonus;
}
public void setBonus(float bonus) {
this.bonus = bonus;
}
public Programmer(String name, float salary, float bonus) {
super(name, salary);
this.bonus = bonus;
}
public static void main(String args[]){
Programmer p=new Programmer("Đỗ Trung Quân", 1000, 500);
System.out.println("Tên lập trình viên : " + p.getName());
System.out.println("Luong Lap trinh vien : "+p.getSalary());
System.out.println("Bonus cua Lap trinh vien :"+p.getBonus());
}
}
Output:
Tên lập trình viên : Đỗ Trung Quân
Lương Lập trình viên : 1000.0
Bonus của lập trình viên : 500.0
Giải thích:
- Class Programmer mình không khai báo 2 biến name và salary nhưng nó vẫn sử dụng được. Vì Programmer đã kế thừa class Employee -> nó có thể sử dụng lại các constructor và get/set từ class cha. Kêu gọi chúng bằng từ khóa “super”
Tuy nhiên trong C++ không cho phép làm điều này nếu 2 biến ở class cha là private. Bạn có thể tham khảo link bên dưới để biết cách truy cập biến và hàm private lớp cha từ lớp con trong C++
-> Lớp bạn và lớp dẫn xuất trong C++
(chú ý, trong java không có override biến mà chỉ có method).
Nếu bạn khai báo 1 biến name hoặc salary khác trong clas Programmer. Nó sẽ là 2 biến hoàn toàn khác 2 biến trong class Employee
- Tính trừu tượng, phương thức ảo:
Có câu “program to interfaces, not to concrete implementations”. Nghĩa là khi viết chương trình theo phong cách hướng đối tượng, khi thiết kế các đối tượng, ta cần rút tỉa ra những đặc trưng của chúng, rồi trừu tượng hóa thành các interface, và thiết kế xem chúng sẽ tương tác với nhau như thế nào. Nói cách khác, chúng ta định ra các interface và các contract mà chúng cần thỏa mãn.
Nói 1 cách đơn giản thì bạn chỉ cần khai báo hàm trong lớp cha (access modifier, phương thức trả về, tên hàm, tham số truyền vào). Còn định nghĩa trong phần thân hàm bạn không cần quan tâm đến. Vì nó sẽ được override lại từ class kế thừa.
Định nghĩa: Đây là khả năng của chương trình bỏ qua hay không chú ý đến một số khía cạnh của thông tin mà nó đang trực tiếp làm việc lên, nghĩa là nó có khả năng tập trung vào những cốt lõi cần thiết (chỉ khai báo). Mỗi đối tượng phục vụ như là một “động tử” có thể hoàn tất các công việc một cách nội bộ, báo cáo, thay đổi trạng thái của nó và liên lạc với các đối tượng khác mà không cần cho biết làm cách nào đối tượng tiến hành được các thao tác (sự override từ lớp con). Tính chất này thường được gọi là sự trừu tượng của dữ liệu.
- Phương thức ảo là phương thức được định nghĩa ở lớp cơ sở (lớp cha) mà các lớp dẫn xuất (lớp con) muốn sử dụng phải định nghĩa lại. Dùng từ khoá virtual (c++) hay abstract (java)để khai báo phương thức ảo:
- Trong Class ảo có thể có phương thức ảo hoặc không nhưng phương thức ảo bắt buộc phải ở trong class ảo
- phương thức ảo không chứa body
- Khi kế thừa class ảo, bắt buộc phải viết lại phương thức ảo của nó
Code C++
virtual <kiểu trả về> <tên phương thức >(<d/s tham số>)
{
....
}
Code java
abstract <kiểu trả về> <tên phương thức >(<d/s tham số>)
{
....
}
Ví dụ
//Phải thêm từ khóa abstract trước class nếu nó chưa method abstract
abstract class Employee{
//method Abstract không có body
abstract public void SayHelloAbstract(String name);
public void SayHello(){
System.out.println("Xin chaof");
}
}
Viết lại class Programmer
class Programmer extends Employee{
private float bonus;
public float getBonus() {
return bonus;
}
public void setBonus(float bonus) {
this.bonus = bonus;
}
@Override // viết lại phương thức SayHelloAbstract
public void SayHelloAbstract(String name){
System.out.println("Xin chào : " + name);
}
public Programmer(String name, float salary, int bonus) {
super(name, salary);
this.bonus = bonus;
}
public static void main(String args[]){
Programmer p=new Programmer("Đỗ Trung Quân", 1000, 500);
p.SayHelloAbstract(p.getName());
System.out.println("Luong của bạn tháng này : "+p.getSalary());
System.out.println("Bonus cua bạn tháng này : "+p.getBonus());
}
}
Output:
Xin chào : Đỗ Trung Quân
Lương của bạn tháng này : 1000.0
Bonus cua bạn tháng này : 500.0
-Tính đa hình (polymorphism)
- poly (nhiều) + phism(body) = nhiều hình thái. Tính đa hình được thể hiện qua việc viết lại các method(hàm) từ class cha thông qua class kế thừa nó hoặc việc triển khai các interface.
Giả sử ta có 1 class abstract Animals và 3 class Ducks, Cats, Dogs sẽ kế thừa animals
Trong hình ảnh vịt. chó và mèo đều kế thừa class Animals
abstract class Animals{
private String name;
public Animals() {
}
public Animals(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void Speak(String name, String sound){
System.out.println("Animals Speak!" );
}
}
//Class Ducks kế thừa Animals
class Ducks extends Animals{
public Ducks(String name) {
super(name);
}
@Override //viết lại hàm peak
public void Speak(String name, String sound){
System.out.println(name + " speaks: " + sound);
}
}
//Class Dogs
class Dogs extends Animals{
public Dogs(String name) {
super(name);
}
@Override //viết lại hàm peak
public void Speak(String name, String sound){
System.out.println(name + " speaks: " + sound);
}
}
//Class Cat
class Cats extends Animals{
public Cats(String name) {
super(name);
}
}
Và hàm main
public static void main(String[] args) {
//Tạo ra 3 đối tượng dog, cat ,duck
Dogs dog = new Dogs("Dog");
Ducks duck = new Ducks("Duck");
Cats cat = new Cats("Cat");
// gọi hàm Speak
dog.Speak(dog.getName(), "Woof");
duck.Speak(duck.getName(), "Quack");
cat.Speak(cat.getName(), "Meow");
}
Output:
Dog speaks: Woof
Duck speaks: Quack
Animals Speak!
Ở trên mình đã không override lại method Speak cho class Cats và bạn thấy. Khi mình gọi hàm nó sẽ refer đến Speak ở class cha (Animals) và in ra “Animals Speake!” thay vì “Cat speak: Meow” Như Dog và Duck.
Và đó là 4 đặc điểm chính trong lập trình hướng đối tượng OOP