Xin chào! Bạn có bao giờ thắc mắc tại sao Java lại được thiết kế như vậy không? Theo nghĩa là bạn tạo các lớp, dựa trên chúng - các đối tượng, các lớp có các phương thức, v.v. Nhưng tại sao cấu trúc của ngôn ngữ lại sao cho các chương trình bao gồm các lớp và đối tượng chứ không phải thứ gì khác? Tại sao khái niệm “vật thể” được phát minh và đặt lên hàng đầu? Có phải tất cả các ngôn ngữ đều hoạt động theo cách này và nếu không, nó mang lại lợi ích gì cho Java? Như bạn có thể thấy, có rất nhiều câu hỏi :) Hãy thử trả lời từng câu hỏi trong bài giảng hôm nay.
Kristen Nygaard và Ole Johan Dahl - người tạo ra Simula
Có vẻ như Simula là một ngôn ngữ cổ xưa theo tiêu chuẩn lập trình, nhưng mối liên hệ “gia đình” của chúng với Java có thể nhìn thấy bằng mắt thường. Rất có thể, bạn có thể dễ dàng đọc mã được viết trên đó và giải thích một cách chung chung về chức năng của nó :)
Nguyên tắc OOP:
Lập trình hướng đối tượng (OOP) là gì
Tất nhiên, Java được tạo thành từ các đối tượng và các lớp là có lý do. Đây không phải là ý tưởng bất chợt của những người sáng tạo ra nó, hay thậm chí là phát minh của họ. Có nhiều ngôn ngữ khác dựa trên đối tượng. Ngôn ngữ đầu tiên như vậy được gọi là Simula và nó được phát minh vào những năm 1960 ở Na Uy. Trong số những thứ khác, Simula đã giới thiệu các khái niệm về “ lớp ” và “ phương pháp ”.Begin
Class Rectangle (Width, Height); Real Width, Height;
Begin
Real Area, Perimeter;
Procedure Update;
Begin
Area := Width * Height;
OutText("Rectangle is updating, Area = "); OutFix(Area,2,8); OutImage;
Perimeter := 2*(Width + Height);
OutText("Rectangle is updating, Perimeter = "); OutFix(Perimeter,2,8); OutImage;
End of Update;
Update;
OutText("Rectangle created: "); OutFix(Width,2,6);
OutFix(Height,2,6); OutImage;
End of Rectangle;
Rectangle Class ColouredRectangle (Color); Text Color;
Begin
OutText("ColouredRectangle created, color = "); OutText(Color);
OutImage;
End of ColouredRectangle;
Ref(Rectangle) Cr;
Cr :- New ColouredRectangle(10, 20, "Green");
End;
Ví dụ mã được lấy từ bài viết Simula - 50 năm OOP . Như bạn có thể thấy, Java và tổ tiên của nó không quá khác biệt với nhau :) Điều này là do sự xuất hiện của Simula đánh dấu sự ra đời của một khái niệm mới - lập trình hướng đối tượng. Wikipedia đưa ra định nghĩa sau về OOP: Lập trình hướng đối tượng (OOP) là một phương pháp lập trình dựa trên việc biểu diễn một chương trình dưới dạng một tập hợp các đối tượng, mỗi đối tượng là một thể hiện của một lớp cụ thể và các lớp tạo thành một hệ thống phân cấp kế thừa. Theo tôi, nó rất thành công. Gần đây bạn đã bắt đầu học Java, nhưng hầu như không có từ nào trong đó là xa lạ với bạn :) Ngày nay, OOP là phương pháp lập trình phổ biến nhất. Bên cạnh Java, nguyên tắc OOP được sử dụng trong nhiều ngôn ngữ phổ biến mà có thể bạn đã từng nghe tới. Đó là C++ (được các nhà phát triển trò chơi máy tính sử dụng tích cực), Objective-C và Swift (họ viết chương trình cho thiết bị Apple), Python (có nhu cầu cao nhất trong học máy), PHP (một trong những ngôn ngữ phát triển web phổ biến nhất), JavaScript (nói đơn giản hơn là họ không làm gì với nó) và nhiều thứ khác. Thực ra, những “nguyên tắc” này của OOP là gì? Hãy cho bạn biết chi tiết hơn.
Nguyên tắc OOP
Đây là điều cơ bản. 4 tính năng chính cùng nhau tạo thành mô hình lập trình hướng đối tượng. Hiểu chúng là chìa khóa để trở thành một lập trình viên thành công.Nguyên tắc 1. Kế thừa
Tin vui là bạn đã quen với một số nguyên tắc của OOP! :) Chúng tôi đã gặp phải tính kế thừa một vài lần trong các bài giảng và chúng tôi đã có thời gian làm việc với nó. Kế thừa là một cơ chế cho phép bạn mô tả một lớp mới dựa trên lớp (cha mẹ) hiện có. Trong trường hợp này, các thuộc tính và chức năng của lớp cha được lớp mới mượn. Tại sao việc thừa kế là cần thiết và nó mang lại lợi ích gì? Trước hết, tái sử dụng mã. Các trường và phương thức được mô tả trong lớp cha có thể được sử dụng trong các lớp con. Nếu tất cả các loại ô tô đều có 10 trường chung và 5 phương thức giống nhau thì bạn chỉ cần đặt chúng vào lớp chaAuto
. Bạn có thể sử dụng chúng trong các lớp con cháu mà không gặp vấn đề gì. Ưu điểm vững chắc: cả về mặt định lượng (ít mã hơn) và kết quả là về mặt chất lượng (các lớp trở nên đơn giản hơn nhiều). Đồng thời, cơ chế kế thừa rất linh hoạt và bạn có thể thêm riêng chức năng còn thiếu vào phần con (một số trường hoặc hành vi cụ thể cho một lớp cụ thể). Nói chung, cũng như trong cuộc sống đời thường: tất cả chúng ta đều giống cha mẹ mình ở một số điểm, nhưng khác với họ ở một số điểm :)
Nguyên tắc 2. Trừu tượng hóa
Đây là một nguyên tắc rất đơn giản. Trừu tượng hóa có nghĩa là làm nổi bật những đặc điểm chính, quan trọng nhất của một đối tượng và ngược lại - loại bỏ những đặc điểm phụ, không quan trọng. Chúng ta đừng phát minh lại bánh xe và nhớ lại một ví dụ từ một bài giảng cũ về các lớp học. Giả sử chúng ta đang tạo một tủ hồ sơ gồm các nhân viên của công ty. Để tạo các đối tượng nhân viên, chúng tôi đã viết một lớpEmployee
. Những đặc điểm nào là quan trọng đối với mô tả của họ trong hồ sơ công ty? Họ tên, ngày sinh, số an sinh xã hội, mã số thuế. Nhưng không chắc trong một tấm thẻ loại này, chúng ta cần có chiều cao, màu mắt và màu tóc của anh ấy. Công ty không cần thông tin này về nhân viên. Do đó, đối với lớp, Employee
chúng ta sẽ đặt các biến String name
, int age
, int socialInsuranceNumber
và int taxNumber
, và chúng ta sẽ loại bỏ những thông tin không cần thiết đối với chúng ta, chẳng hạn như màu mắt và trừu tượng hóa nó. Nhưng nếu chúng ta tạo một danh mục người mẫu ảnh cho một đại lý thì tình hình sẽ thay đổi đáng kể. Để mô tả một người mẫu thời trang, chiều cao, màu mắt và màu tóc rất quan trọng đối với chúng ta nhưng không cần đến số TIN. Vì vậy, trong lớp Model
chúng ta tạo các biến String height
, String hair
, String eyes
.
Nguyên tắc 3: Đóng gói
Chúng tôi đã gặp phải nó rồi. Đóng gói trong Java có nghĩa là hạn chế quyền truy cập vào dữ liệu và khả năng thay đổi dữ liệu đó. Như bạn có thể thấy, nó dựa trên từ “viên nang”. Trong “viên nang” này, chúng tôi ẩn một số dữ liệu quan trọng mà chúng tôi không muốn bất kỳ ai thay đổi. Một ví dụ đơn giản từ cuộc sống. Bạn có họ và tên. Mọi người bạn biết đều biết họ. Nhưng họ không có quyền thay đổi họ và tên của bạn. Người ta có thể nói, quá trình này được “đóng gói” trong văn phòng hộ chiếu: bạn chỉ có thể thay đổi họ và tên của mình ở đó và chỉ bạn mới có thể làm điều đó. Những “người dùng” khác có quyền truy cập chỉ đọc vào họ và tên của bạn :) Một ví dụ khác là số tiền trong căn hộ của bạn. Để chúng ở nơi dễ thấy ở giữa phòng không phải là một ý kiến hay. Bất kỳ “người dùng” nào (người đến nhà bạn) đều có thể thay đổi số tiền của bạn, tức là. nhặt chúng lên. Tốt hơn là nên gói chúng trong két sắt. Chỉ bạn mới có quyền truy cập và chỉ với một mã đặc biệt. Các ví dụ rõ ràng về đóng gói mà bạn đã làm việc là các công cụ sửa đổi truy cập (private
, public
v.v.) và getter-setters. Nếu trường age
lớp Cat
không được đóng gói, bất kỳ ai cũng có thể viết:
Cat.age = -1000;
Và cơ chế đóng gói cho phép chúng ta bảo vệ trường age
bằng phương thức setter, trong đó chúng ta có thể kiểm tra xem tuổi không thể là số âm.
Nguyên tắc 4. Đa hình
Đa hình là khả năng xử lý nhiều loại như thể chúng là cùng một loại. Trong trường hợp này, hành vi của các đối tượng sẽ khác nhau tùy thuộc vào loại mà chúng thuộc về. Nghe có vẻ hơi phức tạp? Hãy tìm ra nó ngay bây giờ. Hãy lấy ví dụ đơn giản nhất - động vật. Hãy tạo một lớpAnimal
với một phương thức duy nhất - voice()
, và hai lớp con của nó - Cat
và Dog
.
public class Animal {
public void voice() {
System.out.println("Voice!");
}
}
public class Dog extends Animal {
@Override
public void voice() {
System.out.println("Bow-wow!");
}
}
public class Cat extends Animal {
@Override
public void voice() {
System.out.println("Meow!");
}
}
Bây giờ hãy thử tạo một liên kết Animal
và gán cho nó một đối tượng Dog
.
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.voice();
}
}
Bạn nghĩ phương pháp nào sẽ được gọi? Animal.voice()
hoặc Dog.voice()
? Phương thức lớp sẽ được gọi là Dog
: Woof-woof! Chúng tôi đã tạo một tham chiếu Animal
nhưng đối tượng hoạt động như Dog
. Nếu cần, anh ta có thể cư xử như một con mèo, một con ngựa hoặc một con vật khác. Điều chính là gán một tham chiếu kiểu chung Animal
cho một đối tượng của một lớp con cụ thể. Điều này hợp lý vì tất cả chó đều là động vật. Đây chính là ý của chúng tôi khi nói “các đối tượng sẽ hoạt động khác nhau tùy thuộc vào loại của chúng”. Nếu chúng ta tạo một đối tượng Cat
−
public static void main(String[] args) {
Animal cat = new Cat();
cat.voice();
}
phương thức voice()
sẽ xuất ra "Meo meo!" “Khả năng làm việc với nhiều loại như thể chúng cùng loại” nghĩa là gì? Điều này cũng khá dễ dàng. Hãy tưởng tượng rằng chúng ta đang tạo một tiệm làm tóc cho động vật. Tiệm làm tóc của chúng tôi phải có khả năng cắt tất cả các con vật, vì vậy chúng tôi sẽ tạo một phương thức shear()
(“cắt”) với một tham số Animal
- con vật mà chúng tôi sẽ cắt.
public class AnimalBarbershop {
public void shear(Animal animal) {
System.out.println("The haircut is ready!");
}
}
Và bây giờ chúng ta có thể truyền shear
cả đối tượng Cat
và đối tượng cho phương thức Dog
!
public static void main(String[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
AnimalBarbershop barbershop = new AnimalBarbershop();
barbershop.shear(cat);
barbershop.shear(dog);
}
Đây là một ví dụ rõ ràng: lớp AnimalBarbershop
làm việc với các kiểu Cat
như Dog
thể chúng là cùng một kiểu. Đồng thời, họ có những hành vi Cat
khác nhau Dog
: họ sử dụng giọng nói của mình một cách khác nhau.
GO TO FULL VERSION