CodeGym /Blog Java /Ngẫu nhiên /Khái niệm OOP trong Java

Khái niệm OOP trong Java

Xuất bản trong nhóm
Một trong những thế mạnh lớn nhất của Java là lập trình hướng đối tượng (OOP). Đó là lý do tại sao ngôn ngữ này trở nên phổ biến và rất phù hợp cho các dự án ở mọi quy mô. Lập trình hướng đối tượng là gì? Nó không phải là ma thuật, nhưng nó có vẻ kỳ diệu nếu bạn thực sự tham gia vào nó. OOP là về cách xây dựng phần mềm của bạn. Đó là một khái niệm, hay đúng hơn là một loạt các khái niệm oop trong Java, cho phép bạn tạo một số tương tác và mối quan hệ cụ thể giữa các đối tượng Java để phát triển và sử dụng phần mềm một cách hiệu quả. Khái niệm OOP trong Java - 1OOP cổ điển bao gồm 3+1 khái niệm chính. Hãy bắt đầu với những tác phẩm kinh điển.

đối tượng

Các đối tượng Java cũng như các đối tượng trong thế giới thực đều có hai đặc điểm: trạng thái và hành vi.

Ví dụ đối tượng Human có trạng thái (tên, giới tính, ngủ hay không…) và hành vi (học Java, đi, nói…). Bất kỳ đối tượng Java nào cũng lưu trữ trạng thái của nó trong các trường và thể hiện hành vi của nó thông qua các phương thức.

đóng gói

Đóng gói dữ liệu đang ẩn dữ liệu nội bộ khỏi thế giới bên ngoài và chỉ truy cập dữ liệu đó thông qua các phương pháp được hiển thị công khai. Điều đó nghĩa là gì? dữ liệu gì? Trốn tránh ai? Ẩn có nghĩa là hạn chế quyền truy cập trực tiếp vào các thành viên dữ liệu (trường) của một lớp.

Cách nó hoạt động trong Java:

  1. Các trường được đặt ở chế độ riêng tư
  2. Mỗi trường trong một lớp có hai phương thức đặc biệt: getter và setter. Các phương thức Getter trả về giá trị của trường. Các phương thức setter cho phép bạn thay đổi giá trị của trường theo cách gián tiếp nhưng được phép.

Ví dụ về đóng gói trong mã Java:


public class Student {
private int age;
private String name;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

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

public class Test{
public static void main(String[] args) {
Student firstStudent = new Student();
firstStudent.setName("John");
// The name field is private, so you can no longer do this:  firstStudent.name = "John"; 
}
}

Tại sao bạn nên sử dụng đóng gói?

Lý do chính là để giúp bạn thay đổi mã dễ dàng hơn. Hãy tưởng tượng bạn có một ứng dụng cho một trường khúc côn cầu và có một lớp HockeyStudent với hai trường lưu trữ tên và tuổi của học sinh khi người đó đăng ký học tại trường. Một cái gì đó như thế này:

public class HockeyStudent {
public String name;
public  int ageOfEnrollment;
}
Trường ageOfEnrollment là công khai, không có getters hoặc setters… Lớp này được sử dụng bởi nhiều lớp khác và mọi thứ đều ổn cho đến khi một số nhà phát triển quyết định rằng một trường int đơn lẻ là không đủ. Một số vận động viên khúc côn cầu trong nhóm lớn hơn các đồng nghiệp của họ gần một tuổi, vì vậy sẽ thuận tiện hơn nếu chia họ thành hai nhóm tùy thuộc vào tháng sinh của họ. Vì vậy, trường ageOfEnrollment nên được thay đổi thành một mảng int (int[][]) : số đầu tiên là số năm đầy đủ và số thứ hai là số tháng. Bây giờ bạn cần cấu trúc lại tất cả mã sử dụng lớp Sinh viên ! Nhưng nếu ageOfEnrollment của bạntrường là riêng tư và bạn có getters và setters, thì mọi thứ sẽ dễ dàng hơn. Nếu yêu cầu đặt tuổi của học sinh thay đổi, chỉ cần cập nhật logic trong phương thức setAgeOfEnrollment() setter và các lớp của bạn có thể tiếp tục sử dụng Học sinh mà không gặp bất kỳ sự cố nào! Ví dụ này hơi giả tạo, nhưng tôi hy vọng nó giải thích lý do tại sao sử dụng đóng gói là một ý tưởng tuyệt vời.

Di sản

Nguyên tắc này dễ hiểu hơn ngay cả khi không có kinh nghiệm thực tế. Đừng lặp lại chính mình (DRY) có thể là phương châm cho khái niệm kế thừa. Kế thừa cho phép bạn tạo một lớp con kế thừa các trường và phương thức của lớp cha mà không cần định nghĩa lại chúng. Chắc chắn, bạn có thể ghi đè các trường và phương thức của lớp cha trong lớp con, nhưng điều đó không cần thiết. Hơn nữa, bạn có thể thêm các trạng thái và hành vi mới trong lớp con. Các lớp cha đôi khi được gọi là lớp cha hoặc lớp cơ sở, và các lớp con được gọi là lớp con. Từ khóa mở rộng của Java được sử dụng để thực hiện nguyên tắc kế thừa trong mã.

Cách nó hoạt động trong Java:

  1. Tạo lớp cha.
  2. Tạo lớp con bằng từ khóa mở rộng .
  3. Trong hàm tạo của lớp Con, sử dụng phương thức super(parentField1, parentField2, ...) để đặt các trường của lớp cha.

Hàm tạo là một phương thức đặc biệt được sử dụng để khởi tạo một đối tượng mới được tạo. Một hàm tạo có cùng tên với tên lớp của nó. Có hai loại hàm tạo: mặc định (hàm tạo không có đối số) và hàm tạo được tham số hóa. Một lớp phải có ít nhất một hàm tạo (nó có hàm tạo mặc định nếu chưa định nghĩa các hàm tạo khác) và nó có thể có rất nhiều hàm tạo.

Mỗi khi bạn tạo một đối tượng mới, bạn gọi hàm tạo của nó. Trong ví dụ trên, bạn làm điều này trong dòng này:


Student firstStudent = new Student();

Bạn sử dụng từ khóa new để gọi phương thức khởi tạo mặc định của lớp Student : tudent() .

Một số quy tắc:

  1. Một lớp chỉ có thể có một phụ huynh.
  2. Một lớp cha có thể có nhiều lớp con.
  3. Một lớp con có thể có các lớp con của chính nó.

Ví dụ về kế thừa trong mã Java

Hãy tạo một lớp Điện thoại .

public class Phone {
    int price;
    double weight;

// Constructor
public Phone(int price, double weight) {
        this.price = price;
        this.weight = weight;
    }

    void orderPhone(){
        System.out.println("Ordering phone...");
    }
}
Tất nhiên, có nhiều loại điện thoại khác nhau, vì vậy hãy tạo hai lớp con: một cho điện thoại Android và lớp thứ hai cho iPhone. Sau đó, chúng tôi sẽ thêm một số trường và phương thức mà cấp độ gốc không có. Và chúng ta sẽ sử dụng super() để gọi các hàm khởi tạo để khởi tạo các trường mà lớp cha mẹ có.

Ví dụ về kế thừa trong Java


public class Android extends Phone {

// Some new fields     
String androidVersion;
int screenSize;

    String secretDeviceCode;

// Constructor 
    public Android(int price, double weight, String androidVersion, int screenSize, String secretDeviceCode) {
        super(price, weight); // Android inherits Phone’s fields

        //this - reference to the current object
        //super - reference to the parent object

        this.androidVersion = androidVersion;
        this.screenSize = screenSize;
        this.secretDeviceCode = secretDeviceCode;
    }

	// New Android-specific method, does not exist in the Phone class 
    void installNewAndroidVersion() {
        System.out.println("installNewAndroidVersion invoked...");

    }

}

public class IPhone extends Phone {
   
    boolean fingerPrint;

    public IPhone(int price, double weight, boolean fingerPrint) {
        super(price, weight);
        System.out.println("IPhone constructor was invoked...");
        this.fingerPrint = fingerPrint;
    }

    void deleteIPhoneFromDb() {
        System.out.println("deleteIPhoneFromDb invoked...");
    }

@Override // This is about polymorphism, see below
void orderPhone(){
        System.out.println("Ordering my new iPhone and deleting the old one...");
    }
}
Vì vậy, xin nhắc lại: trong Java, tính kế thừa cho phép bạn mở rộng một lớp với các lớp con kế thừa các trường và phương thức của lớp cha. Đó là một cách tuyệt vời để đạt được khả năng sử dụng lại mã.

đa hình

Đa hình là khả năng biến hình của một đối tượng, có các dạng khác nhau hoặc đúng hơn là hành động theo những cách khác nhau. Trong Java, tính đa hình thường xảy ra khi một tham chiếu lớp cha được sử dụng để chỉ một đối tượng lớp con.

Điều đó có nghĩa là gì và nó hoạt động như thế nào trong Java:

Tính đa hình trong Java là gì? Nói chung, điều đó có nghĩa là bạn có thể sử dụng cùng một tên phương thức cho các mục đích khác nhau. Có hai loại đa hình trong Java: ghi đè phương thức (đa hình động) và nạp chồng phương thức (đa hình tĩnh).

Ghi đè phương thức

Bạn có thể ghi đè phương thức của lớp cha trong lớp con, buộc nó phải hoạt động theo cách khác. Hãy tạo một lớp cha Nhạc sĩ với phương thức play() .

Ví dụ về tính đa hình trong mã Java


   public class Musician {
    String name;
    int age;

    // Default constructor
    public Musician() {
    }

    // Parameterized constructor
    public Musician(String name, int age) {
        this.name = name;
        this.age = age;
    }

    void play() {
        System.out.println("I am playing my instrument...");
    }
}
Các nhạc sĩ khác nhau sử dụng các nhạc cụ khác nhau. Hãy tạo hai lớp con: PianistViolinist . Nhờ tính đa hình, mỗi cái sẽ thực thi phiên bản riêng của phương thức play() . Khi ghi đè, bạn có thể sử dụng chú thích @Override nhưng không cần thiết.

public class Pianist extends Musician {
    
    String favoritePianoType;

    public Pianist(String name, int age, String favoritePianoType) {
        super(name, age);
        this.favoritePianoType = favoritePianoType;
    }


    @Override
void play(){
        System.out.println("I am playing the piano...");
    }
}
Người chơi vĩ cầm có thể là nghệ sĩ độc tấu hoặc thành viên của dàn nhạc. Hãy cân nhắc điều đó khi ghi đè phương thức play() của chúng ta .

public class Violinist extends Musician { 
    boolean isSoloist; 

public Violinist(String name, int age, boolean isSoloist) {
            super(name, age);
            this.isSoloist = isSoloist;
        }


    @Override
void play(){
if (isSoloist) 
        System.out.println("I am playing the violin solo...");
else 
System.out.println("I am playing the violin in an orchestra...");

    }
}
Hãy tạo một lớp Demo , trong đó chúng ta sẽ tạo ba đối tượng, một thể hiện của mỗi lớp đã tạo trước đó. Chúng ta sẽ thấy những kết quả chúng ta nhận được.

public class Demo {
  public static void main(String[] args) {
  Musician musician = new Musician();
  Violinist violinist = new Violinist("John", 32, true);
  Pianist pianist = new Pianist("Glen", 30, "Acoustic"); 

  System.out.println("Musician said:");
  musician.play();
  System.out.println("Violinist said:");
  violinist.play();
  System.out.println("Pianist said:");
  pianist.play();
    }
}
Đây là những gì chúng tôi nhận được:

Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo…
Pianist said:
I am playing the piano...
Mỗi nghệ sĩ vĩ cầm và nghệ sĩ piano đều là nhạc sĩ, nhưng không phải nhạc sĩ nào cũng là nghệ sĩ vĩ cầm hoặc nghệ sĩ piano. Điều đó có nghĩa là bạn có thể sử dụng phương pháp chơi của nhạc sĩ nếu bạn không cần tạo một phương pháp mới. Hoặc bạn có thể gọi phương thức của cha từ con bằng từ khóa super . Hãy làm điều đó trong mã của Pianist:

public class Pianist extends Musician {

    String favoritePianoType;
    
    @Override
    void play(){
        super.play();
        System.out.println("I am playing the piano...");
    }
}
Bây giờ, hãy gọi phương thức main() của chúng ta trong lớp Demo . Đây là kết quả:

Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...

nạp chồng phương thức

Nạp chồng phương thức có nghĩa là sử dụng nhiều phương thức khác nhau có cùng tên trong cùng một lớp. Chúng phải khác nhau về số lượng, thứ tự hoặc loại tham số của chúng. Giả sử rằng một nghệ sĩ piano có thể chơi piano acoustic và piano điện. Để chơi đàn điện, nhạc công cần có điện. Hãy tạo hai phương thức play() khác nhau . Cái đầu tiên không có thông số, dành cho đàn piano acoustic và cái thứ hai có thông số cho biết có điện hay không.

public class Pianist extends Musician {

    String name;
    int age;
    String favoritePianoType;

    @Override
    void play(){
        super.play();
        System.out.println("I am playing the piano...");
    }
    void play(boolean isElectricity){
        if (isElectricity) {
            System.out.println("The electricity is on.");
            System.out.println("I am playing the piano...");
        }
        else System.out.println("I can't play this without electricity.");
    }
}
Nhân tiện, bạn có thể sử dụng phương thức play() đầu tiên bên trong phương thức play(boolean) thứ hai theo cách này:

void play(boolean isElectricity){
        if (isElectricity) {
            System.out.println("The electricity is on.");
            play();
        }
        else System.out.println("I can't play this without electricity.");
    }
Hãy thêm một số dòng vào lớp Demo của chúng tôi để chứng minh quá tải của chúng tôi:

public class Demo {
    public static void main(String[] args) {

        Musician musician = new Musician();
        Violinist violinist = new Violinist("John", 23, true);
        Pianist pianist = new Pianist("Glen", 30, "Acoustic"); 

        System.out.println("Musician said:");
        musician.play();
        System.out.println("Violinist said:");
        violinist.play();
        System.out.println("Pianist said:");
        pianist.play();
        System.out.println("The pianist will now try the electric piano:");
        pianist.play(true);
        System.out.println("The electricity has been shut off. Now when trying the electric piano, the pianist says:");
        pianist.play(false);
    }
}
Đây là kết quả:

Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...
The pianist will now try the electric piano:
The electricity is on.
I am playing my instrument...
I am playing the piano...
The electricity has been shut off. Now when trying the electric piano, the pianist says:
I can't play this without electricity.
Java biết nên sử dụng phương thức nào dựa trên các tham số của nó và loại đối tượng. Đó là tính đa hình.

trừu tượng

Khi chúng ta định nghĩa một lớp, chúng ta đang cố gắng xây dựng một mô hình của một thứ gì đó. Ví dụ: giả sử chúng ta đang viết một trò chơi điện tử tên là MyRacer với các loại xe đua khác nhau. Người chơi có thể chọn một trong số chúng và sau đó cập nhật nó hoặc mua một cái khác. Vậy… Xe hơi là gì? Ô tô là một thứ khá phức tạp, nhưng nếu chúng ta đang cố gắng tạo một trò chơi điện tử đua xe (trái ngược với trò chơi mô phỏng lái xe), thì chúng ta không cần phải mô tả tất cả hàng nghìn bánh răng và vòng đệm mà nó chứa. Chúng tôi cần kiểu dáng, tốc độ tối đa, đặc điểm khả năng cơ động, giá cả, màu sắc… Và có lẽ thế là đủ. Đó là mô hình của một chiếc xe hơi cho trò chơi của chúng tôi. Sau này trong MyRacer 2, giả sử chúng tôi quyết định thêm các loại lốp ảnh hưởng đến khả năng xử lý trên đường. Ở đây mô hình là khác nhau, bởi vì chúng tôi đã thêm nhiều chi tiết hơn. Cho phép' s định nghĩa trừu tượng hóa dữ liệu là quá trình chỉ xác định các đặc điểm quan trọng (hoặc cần thiết) của một đối tượng và bỏ qua mọi chi tiết không liên quan. Có nhiều mức độ trừu tượng khác nhau. Ví dụ, nếu bạn là hành khách trên xe buýt, bạn cần biết xe buýt của mình trông như thế nào và nó sẽ đi đâu, nhưng bạn không cần biết cách lái xe. Nếu bạn là tài xế xe buýt, bạn không cần biết cách tạo xe buýt mới—bạn chỉ cần biết cách lái xe buýt đó. Nhưng nếu bạn là một nhà sản xuất xe buýt, bạn cần chuyển sang mức độ trừu tượng thấp hơn, bởi vì các chi tiết của thiết kế xe buýt rất quan trọng đối với bạn. Tôi hi vọng bạn hiểu những gì tôi nói. bạn cần biết xe buýt của bạn trông như thế nào và nó sẽ đi đâu, nhưng bạn không cần phải biết lái nó. Nếu bạn là tài xế xe buýt, bạn không cần biết cách tạo xe buýt mới—bạn chỉ cần biết cách lái xe buýt đó. Nhưng nếu bạn là một nhà sản xuất xe buýt, bạn cần chuyển sang mức độ trừu tượng thấp hơn, bởi vì các chi tiết của thiết kế xe buýt rất quan trọng đối với bạn. Tôi hi vọng bạn hiểu những gì tôi nói. bạn cần biết xe buýt của bạn trông như thế nào và nó sẽ đi đâu, nhưng bạn không cần phải biết lái nó. Nếu bạn là tài xế xe buýt, bạn không cần biết cách tạo xe buýt mới—bạn chỉ cần biết cách lái xe buýt đó. Nhưng nếu bạn là một nhà sản xuất xe buýt, bạn cần chuyển sang mức độ trừu tượng thấp hơn, bởi vì các chi tiết của thiết kế xe buýt rất quan trọng đối với bạn. Tôi hi vọng bạn hiểu những gì tôi nói.

Cách nó hoạt động trong Java:

Hãy xây dựng bốn mức độ trừu tượng trong Java, hay đúng hơn là trong OOP — từ mức thấp nhất (cụ thể nhất) đến mức cao nhất (trừu tượng nhất).
  1. Mức trừu tượng thấp nhất là một đối tượng cụ thể. Nó là một thực thể với một tập hợp các đặc điểm thuộc về một lớp cụ thể. Nó có các giá trị trường cụ thể

  2. Khuôn mẫu để tạo đối tượng là một lớp. Đó là mô tả về một tập hợp các đối tượng có thuộc tính và cấu trúc bên trong tương tự nhau.

  3. Một lớp trừu tượng là một mô tả trừu tượng về các đặc điểm của một tập hợp các lớp (nó hoạt động như một khuôn mẫu để các lớp khác kế thừa). Nó có mức độ trừu tượng cao, vì vậy không thể tạo các đối tượng trực tiếp từ một lớp trừu tượng. Chỉ các lớp con của lớp trừu tượng mới có thể được sử dụng để tạo đối tượng. Một lớp trừu tượng có thể bao gồm các phương thức có triển khai, nhưng đây không phải là một yêu cầu.

  4. Một giao diện là một cấu trúc của cấu trúc ngôn ngữ lập trình Java chỉ chứa các phương thức công khai trừu tượng và các trường hằng số tĩnh (tĩnh cuối cùng). Nói cách khác, cả lớp trừu tượng lẫn giao diện đều không thể được sử dụng để tạo đối tượng.

BTW, trong Java 8 trở lên, các giao diện không chỉ có các phương thức trừu tượng và hằng số mà còn cả các phương thức tĩnh và mặc định. Trong Java, một giao diện xác định một hành vi, trong khi một lớp trừu tượng được sử dụng để tạo một hệ thống phân cấp. Một giao diện có thể được thực hiện bởi nhiều lớp.

Ví dụ về giao diện trong mã Java


interface Human {
	public void struggle();
	public void protect();
}

interface Vulcan {
	int angleOfPointyEars; 
	public void turnOffEmotions(boolean isOn);
	public void telepathy();
}
Bạn có thể triển khai nhiều hơn một giao diện

The Spock class implements Human and Vulcan {
public void struggle() {
System.out.println("I am struggling...");
}
	public void protect() {
System.out.println("You are under my protection!”);
}
public void turnOffEmotions(boolean isOn){
If (isOn) {
System.out.println("I am turning off my emotions.");
isOn= !isOn;
}
}
	public void telepathy() {
System.out.println("Connecting to your brain...");
}

}
Đối với những sinh viên mới bắt đầu, nó bao gồm tất cả các khái niệm chính về lập trình hướng đối tượng trong Java. Bên cạnh 4 nguyên tắc OOP chính, Java còn có liên kết, tổng hợp và thành phần. Bạn có thể gọi chúng là "các nguyên tắc OOP bổ sung". Họ xứng đáng với bài viết riêng của họ.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION