JavaRush /Blog Java /Random-VI /Nguyên tắc OOP

Nguyên tắc OOP

Xuất bản trong nhóm
Java là một ngôn ngữ hướng đối tượng. Điều này có nghĩa là bạn cần viết các chương trình Java theo phong cách hướng đối tượng. Và phong cách này dựa trên việc sử dụng các đối tượng và lớp trong chương trình.

Nguyên tắc cơ bản của OOP:

Nguyên tắc OOP - 1Chúng ta hãy thử, với sự trợ giúp của các ví dụ, để hiểu lớp và đối tượng là gì, cũng như cách áp dụng các nguyên tắc cơ bản của OOP trong thực tế: trừu tượng, kế thừa, đa hình và đóng gói.

Một đối tượng là gì?

Thế giới chúng ta đang sống bao gồm các đồ vật. Nếu nhìn xung quanh, chúng ta sẽ thấy xung quanh mình là nhà cửa, cây cối, ô tô, đồ đạc, bát đĩa, máy tính. Tất cả những vật phẩm này đều là đồ vật và mỗi vật phẩm đều có một tập hợp các đặc điểm, hành vi và mục đích cụ thể. Chúng ta đã quen với các đồ vật và luôn sử dụng chúng cho những mục đích rất cụ thể. Ví dụ, nếu chúng ta cần đi làm, chúng ta sử dụng ô tô, nếu muốn ăn, chúng ta dùng bát đĩa, và nếu cần thư giãn, chúng ta cần một chiếc ghế sofa thoải mái. Một người đã quen với việc suy nghĩ khách quan để giải quyết các vấn đề trong cuộc sống hàng ngày. Đây là một trong những lý do sử dụng đối tượng trong lập trình và cách tiếp cận tạo chương trình này được gọi là hướng đối tượng. Hãy đưa ra một ví dụ. Hãy tưởng tượng rằng bạn đã phát triển một mẫu điện thoại mới và muốn đưa nó vào sản xuất hàng loạt. Là một nhà thiết kế điện thoại, bạn biết nó dùng để làm gì, hoạt động như thế nào và bao gồm những bộ phận nào (vỏ, micrô, loa, dây, nút, v.v.). Tuy nhiên, chỉ có bạn mới biết cách kết nối các bộ phận này. Tuy nhiên, bạn không có kế hoạch tự mình sản xuất điện thoại, vì điều này bạn có cả một đội ngũ nhân viên. Để bạn không phải giải thích mỗi lần cách kết nối các bộ phận của điện thoại và để tất cả các điện thoại được sản xuất đều giống nhau, trước khi bắt đầu sản xuất chúng, bạn sẽ cần tạo một bản vẽ dưới dạng một mô tả cấu trúc của điện thoại. Trong OOP, mô tả, bản vẽ, sơ đồ hoặc mẫu như vậy được gọi là lớp, từ đó một đối tượng được tạo khi chương trình được thực thi. Lớp là mô tả về một đối tượng chưa được tạo, giống như một mẫu chung bao gồm các trường, phương thức và hàm tạo, và đối tượng là một thể hiện của lớp được tạo trên cơ sở mô tả này.

Trừu tượng OOP

Bây giờ chúng ta hãy nghĩ về cách chúng ta có thể chuyển từ một đối tượng trong thế giới thực sang một đối tượng trong chương trình, lấy điện thoại làm ví dụ. Lịch sử của phương tiện liên lạc này đã hơn 100 năm và điện thoại hiện đại, không giống như người tiền nhiệm từ thế kỷ 19, là một thiết bị phức tạp hơn nhiều. Khi sử dụng điện thoại, chúng ta không nghĩ về cấu trúc của nó và các quá trình diễn ra bên trong nó. Chúng tôi chỉ cần sử dụng các chức năng do nhà phát triển điện thoại cung cấp - các nút hoặc màn hình cảm ứng để chọn số và thực hiện cuộc gọi. Một trong những giao diện điện thoại đầu tiên là một núm xoay để thực hiện cuộc gọi. Tất nhiên, điều này không thuận tiện lắm. Tuy nhiên, tay cầm đã thực hiện đúng chức năng của nó. Nếu bạn nhìn vào chiếc điện thoại hiện đại nhất và đầu tiên, bạn có thể xác định ngay những chi tiết quan trọng nhất đối với cả một thiết bị từ cuối thế kỷ 19 và một chiếc điện thoại thông minh cực kỳ hiện đại. Đây là thực hiện cuộc gọi (quay số) và nhận cuộc gọi. Về cơ bản, đây là thứ khiến một chiếc điện thoại trở thành một chiếc điện thoại chứ không phải thứ gì khác. Bây giờ chúng ta đã áp dụng nguyên tắc trong OOP - làm nổi bật những đặc điểm và thông tin quan trọng nhất về một đối tượng. Nguyên tắc OOP này được gọi là trừu tượng. Tính trừu tượng trong OOP cũng có thể được định nghĩa là cách biểu diễn các phần tử của một vấn đề trong thế giới thực dưới dạng các đối tượng trong một chương trình. Sự trừu tượng luôn gắn liền với việc khái quát hóa một số thông tin về thuộc tính của đối tượng hoặc đối tượng, vì vậy điều chính là tách thông tin quan trọng khỏi thông tin không quan trọng trong bối cảnh vấn đề đang được giải quyết. Trong trường hợp này, có thể có nhiều mức độ trừu tượng. Hãy thử áp dụng nguyên tắc trừu tượng vào điện thoại của chúng ta. Đầu tiên, hãy điểm qua những loại điện thoại phổ biến nhất từ ​​​​đầu đến nay. Ví dụ, chúng có thể được biểu diễn dưới dạng sơ đồ như trong Hình 1. Nguyên tắc OOP - 2Bây giờ, với sự trợ giúp của tính trừu tượng, chúng ta có thể làm nổi bật thông tin chung trong hệ thống phân cấp đối tượng này: một loại đối tượng trừu tượng phổ biến - điện thoại, một đặc điểm chung của điện thoại - năm ra đời và giao diện chung - tất cả các điện thoại đều có khả năng nhận và gửi cuộc gọi. Đây là những gì nó trông giống như trong Java:
public abstract class AbstractPhone {
    private int year;

    public AbstractPhone(int year) {
        this.year = year;
    }
    public abstract void call(int outputNumber);
    public abstract void ring (int inputNumber);
}
Dựa trên lớp trừu tượng này, chúng ta sẽ có thể tạo các loại điện thoại mới trong chương trình bằng cách sử dụng các nguyên tắc Java OOP cơ bản khác mà chúng ta sẽ xem xét bên dưới.

Đóng gói

Với sự trợ giúp của tính trừu tượng, chúng tôi làm nổi bật những điểm chung của tất cả các đối tượng. Tuy nhiên, mỗi mẫu điện thoại đều mang tính cá nhân và có phần khác biệt so với các mẫu điện thoại khác. Làm thế nào chúng ta có thể vạch ra ranh giới trong chương trình và xác định cá tính này? Làm cách nào chúng tôi có thể đảm bảo rằng không ai trong số người dùng có thể vô tình hoặc cố ý làm hỏng điện thoại của chúng tôi hoặc cố gắng chuyển đổi kiểu máy này sang kiểu máy khác? Đối với thế giới đồ vật thực, câu trả lời rất rõ ràng: bạn cần đặt tất cả các bộ phận vào thân điện thoại. Rốt cuộc, nếu chúng ta không làm điều này và để tất cả phần bên trong của điện thoại cũng như dây kết nối chúng ra bên ngoài, chắc chắn sẽ có một người thử nghiệm tò mò muốn “cải thiện” hoạt động của điện thoại của chúng ta. Để tránh sự can thiệp như vậy vào thiết kế và hoạt động của một đối tượng, OOP sử dụng nguyên tắc đóng gói - một nguyên tắc cơ bản khác của OOP, trong đó các thuộc tính và hành vi của một đối tượng được kết hợp trong một lớp, việc triển khai bên trong của đối tượng được ẩn khỏi người dùng và một giao diện mở được cung cấp để làm việc với đối tượng. Công việc của lập trình viên là xác định thuộc tính và phương thức nào sẽ có thể truy cập công khai và thuộc tính nào là triển khai nội bộ của đối tượng và không nên sửa đổi.

Đóng gói và kiểm soát truy cập

Giả sử rằng trong quá trình sản xuất, thông tin về nó được khắc ở mặt sau điện thoại: năm sản xuất hoặc logo của công ty nhà sản xuất. Thông tin này mô tả khá cụ thể mô hình này - tình trạng của nó. Có thể nói rằng nhà phát triển điện thoại đã quan tâm đến tính bất biến của thông tin này - khó có ai có thể nghĩ đến việc xóa bản khắc. Trong thế giới Java, trạng thái của các đối tượng trong tương lai được mô tả trong một lớp bằng cách sử dụng các trường và hành vi của chúng được mô tả bằng các phương thức. Khả năng thay đổi trạng thái và hành vi được thực hiện bằng cách sử dụng công cụ sửa đổi quyền truy cập vào các trường và phương thức - private, protected, publicdefault(quyền truy cập mặc định). Ví dụ: chúng tôi đã quyết định rằng năm tạo, tên của nhà sản xuất điện thoại và một trong các phương thức thuộc về triển khai nội bộ của lớp và không thể thay đổi bởi các đối tượng khác trong chương trình. Sử dụng mã, lớp có thể được mô tả như sau:
public class SomePhone {

    private int year;
    private String company;
    public SomePhone(int year, String company) {
        this.year = year;
        this.company = company;
    }
private void openConnection(){
    //findComutator
    //openNewConnection...
}
public void call() {
    openConnection();
    System.out.println("I'm calling a number");
}

public void ring() {
    System.out.println("Дзынь-дзынь");
}

 }
Công cụ sửa đổi privatelàm cho các trường và phương thức của một lớp chỉ khả dụng trong lớp đó. Điều này có nghĩa là privatecác trường không thể được truy cập từ bên ngoài và privatecác phương thức cũng không thể được gọi. Việc ẩn quyền truy cập vào một phương thức openConnectioncũng cho chúng ta cơ hội tự do thay đổi cách triển khai bên trong của phương thức này, vì phương thức này được đảm bảo không được các đối tượng khác sử dụng và sẽ không làm gián đoạn hoạt động của chúng. Để làm việc với đối tượng của chúng ta, chúng ta để các phương thức mở callbằng cách sử dụng ringcông cụ sửa đổi public. Việc cung cấp các phương thức công khai để làm việc với một đối tượng cũng là một phần của cơ chế đóng gói, vì nếu quyền truy cập vào một đối tượng bị từ chối hoàn toàn thì nó sẽ trở nên vô dụng.

Di sản

Hãy nhìn vào biểu đồ điện thoại một lần nữa. Bạn có thể thấy rằng nó đại diện cho một hệ thống phân cấp trong đó mô hình nằm bên dưới có tất cả các đặc điểm của các mô hình nằm cao hơn trên nhánh, cộng với đặc điểm của chính nó. Ví dụ: điện thoại thông minh sử dụng mạng di động để liên lạc (có các đặc tính của điện thoại di động), không dây và di động (có các đặc tính của điện thoại không dây) và có thể nhận và thực hiện cuộc gọi (có các đặc tính của điện thoại). Trong trường hợp này, chúng ta có thể nói về sự kế thừa các thuộc tính của đối tượng. Trong lập trình, kế thừa là việc sử dụng các lớp hiện có để định nghĩa các lớp mới. Hãy xem một ví dụ về việc tạo một lớp điện thoại thông minh bằng cách sử dụng tính kế thừa. Tất cả điện thoại không dây đều được cấp nguồn bằng pin sạc có thời gian hoạt động nhất định tính bằng giờ. Vì vậy, hãy thêm thuộc tính này vào lớp điện thoại không dây:
public abstract class WirelessPhone extends AbstractPhone {

    private int hour;

    public WirelessPhone(int year, int hour) {
        super(year);
        this.hour = hour;
    }
    }
callĐiện thoại di động kế thừa các thuộc tính của điện thoại không dây, chúng tôi cũng đã thêm cách triển khai và các phương thức vào lớp này ring:
public class CellPhone extends WirelessPhone {
    public CellPhone(int year, int hour) {
        super(year, hour);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println("Calling a number" + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("A subscriber is calling you" + inputNumber);
    }
}
Và cuối cùng, lớp điện thoại thông minh, không giống như điện thoại di động cổ điển, có hệ điều hành hoàn chỉnh. Bạn có thể thêm các chương trình mới được hệ điều hành này hỗ trợ vào điện thoại thông minh của mình, từ đó mở rộng chức năng của nó. Sử dụng mã, lớp có thể được mô tả như sau:
public class Smartphone extends CellPhone {

    private String operationSystem;

    public Smartphone(int year, int hour, String operationSystem) {
        super(year, hour);
        this.operationSystem = operationSystem;
    }
public void install(String program){
    System.out.println("Installing" + program + "For" + operationSystem);
}

}
Như bạn có thể thấy, Smartphonechúng tôi đã tạo rất ít mã mới để mô tả lớp, nhưng chúng tôi có một lớp mới với chức năng mới. Sử dụng nguyên tắc kế thừa OOP có thể giảm đáng kể số lượng mã và do đó giúp công việc của lập trình viên trở nên dễ dàng hơn.

Đa hình

Nếu chúng ta xem xét tất cả các kiểu điện thoại, thì mặc dù có sự khác biệt về hình dáng và thiết kế của các kiểu máy, nhưng chúng ta có thể xác định được một số hành vi phổ biến ở chúng - chúng đều có thể nhận và thực hiện cuộc gọi cũng như có bộ nút điều khiển khá rõ ràng và đơn giản. Áp dụng một trong những nguyên tắc cơ bản của OOP mà chúng ta đã biết, trừu tượng hóa trong thuật ngữ lập trình, chúng ta có thể nói rằng đối tượng điện thoại có một giao diện chung. Vì vậy, người dùng điện thoại có thể khá thoải mái sử dụng các dòng máy khác nhau bằng cùng một nút điều khiển (cơ hoặc cảm ứng) mà không cần đi sâu vào chi tiết kỹ thuật của máy. Vì vậy, bạn liên tục sử dụng điện thoại di động và bạn có thể dễ dàng thực hiện cuộc gọi từ điện thoại cố định. Nguyên tắc trong OOP khi một chương trình có thể sử dụng các đối tượng có cùng giao diện mà không có thông tin về cấu trúc bên trong của đối tượng được gọi là đa hình . Hãy tưởng tượng rằng trong chương trình của chúng ta, chúng ta cần mô tả một người dùng có thể sử dụng bất kỳ kiểu điện thoại nào để gọi cho người dùng khác. Đây là cách thực hiện:
public class User {
    private String name;

    public User(String name) {
        this.name = name;
            }

    public void callAnotherUser(int number, AbstractPhone phone){
// here it is polymorphism - using the abstract type AbstractPhone phone in the code!
        phone.call(number);
    }
}
 }
Bây giờ hãy mô tả các mẫu điện thoại khác nhau. Một trong những mẫu điện thoại đầu tiên:
public class ThomasEdisonPhone extends AbstractPhone {

public ThomasEdisonPhone(int year) {
    super(year);
}
    @Override
    public void call(int outputNumber) {
        System.out.println("Turn the Handle");
        System.out.println("Give me the phone number, sir");
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Phone calls");
    }
}
Điện thoại cố định thông thường:
public class Phone extends AbstractPhone {

    public Phone(int year) {
        super(year);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println("I'm calling a number" + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Phone calls");
    }
}
Và cuối cùng là một chiếc điện thoại video thú vị:
public class VideoPhone extends AbstractPhone {

    public VideoPhone(int year) {
        super(year);
    }
    @Override
    public void call(int outputNumber) {
        System.out.println("I connect a video channel for the subscriber" + outputNumber );
    }
    @Override
    public void ring(int inputNumber) {
        System.out.println("You have an incoming video call..." + inputNumber);
    }
  }
Hãy tạo các đối tượng trong phương thức main()và kiểm tra phương thức callAnotherUser:
AbstractPhone firstPhone = new ThomasEdisonPhone(1879);
AbstractPhone phone = new Phone(1984);
AbstractPhone videoPhone=new VideoPhone(2018);
User user = new User("Andrey");
user.callAnotherUser(224466,firstPhone);
// Rotate the knob
// Tell me the number of the subscriber, sir
user.callAnotherUser(224466,phone);
//Call number 224466
user.callAnotherUser(224466,videoPhone);
//I connect the video channel for subscriber 224466
Bằng cách gọi cùng một phương thức trên đối tượng user, chúng tôi nhận được các kết quả khác nhau. Việc lựa chọn triển khai phương thức cụ thể calltrong một phương thức callAnotherUserđược thực hiện linh hoạt dựa trên loại đối tượng gọi cụ thể trong quá trình thực thi chương trình. Đây là ưu điểm chính của tính đa hình - sự lựa chọn triển khai trong quá trình thực hiện chương trình. Trong các ví dụ về lớp điện thoại ở trên, chúng tôi đã sử dụng ghi đè phương thức, một kỹ thuật thay đổi cách triển khai phương thức được xác định trong lớp cơ sở mà không thay đổi chữ ký phương thức. Về cơ bản, đây là một phương thức thay thế và chính phương thức mới được định nghĩa trong lớp con sẽ được gọi khi chương trình chạy. Thông thường, khi ghi đè một phương thức, chú thích sẽ được sử dụng @Overrideđể báo cho trình biên dịch kiểm tra chữ ký của các phương thức bị ghi đè và ghi đè. Do đó , để đảm bảo rằng phong cách chương trình của bạn tuân thủ khái niệm OOP và các nguyên tắc của OOP java, hãy làm theo các mẹo sau:
  • làm nổi bật các đặc điểm chính của đối tượng;
  • làm nổi bật các thuộc tính và hành vi chung và sử dụng tính kế thừa khi tạo đối tượng;
  • sử dụng các kiểu trừu tượng để mô tả đối tượng;
  • Cố gắng luôn ẩn các phương thức và trường liên quan đến việc triển khai nội bộ của lớp.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION