JavaRush /Java Blog /Random-TW /物件導向原則

物件導向原則

在 Random-TW 群組發布
Java 是一種物件導向的語言。這意味著您需要使用物件導向的風格來編寫 Java 程式。而這種風格是基於程式中物件和類別的使用。

物件導向程式設計的基本原則:

物件導向程式設計原理 - 1讓我們試著借助範例來了解什麼是類別和對象,以及如何在實務中應用 OOP 的基本原則:抽象、繼承、多態性和封裝。

什麼是對象?

我們所生活的世界是由物體組成的。如果我們環顧四周,我們會發現我們周圍都是房子、樹木、汽車、家具、餐具、電腦。所有這些項目都是對象,每個項目都有一組特定的特徵、行為和目的。我們已經習慣了物體,並且總是將它們用於非常特定的目的。例如,如果我們需要上班,我們需要汽車;如果我們想吃飯,我們需要餐具;如果我們需要放鬆,我們需要一張舒適的沙發。一個人習慣於客觀地思考來解決日常生活中的問題。這是在程式設計中使用物件的原因之一,這種創建程式的方法稱為物件導向。讓我們舉個例子。想像一下,您開發了一款新手機型號,並希望開始大量生產。作為手機設計師,您知道它的用途、功能以及由哪些部分組成(外殼、麥克風、揚聲器、電線、按鈕等)。然而,只有您知道如何連接這些部件。然而,您並不打算親自生產手機;為此,您擁有大量員工。這樣您就不必每次都解釋如何連接手機的各個部件,並且使生產中的所有手機都一樣,在開始生產之前,您需要以電話結構的描述。在 OOP 中,這樣的描述、繪圖、圖表或範本稱為類,在執行程式時從中建立物件。 類別是尚未建立的物件的描述,就像由欄位、方法和建構函式組成的通用模板,而物件是根據此描述建立的類別的實例。

物件導向抽象

現在讓我們考慮如何從現實世界中的物件移動到程式中的對象,以手機為例。這種通訊方式的歷史已超過 100 年,現代電話與其 19 世紀的前身不同,是一種複雜得多的設備。當我們使用手機時,我們不會考慮它的結構和內部發生的過程。我們只需使用手機開發商提供的功能——按鈕或觸控螢幕來選擇號碼並撥打電話。最早的電話介面之一是旋鈕,轉動旋鈕即可撥打電話。當然,這不太方便。儘管如此,手把還是正確地發揮了其功能。如果您查看最現代的第一部電話,您可以立即識別出最重要的細節,這些細節對於 19 世紀末的設備和超現代的智慧型手機都很重要。這是撥打電話(撥打號碼)和接聽電話。從本質上講,這就是手機之所以成為手機而不是其他東西的原因。現在我們已經應用了 OOP 中的原則 - 突出顯示物件最重要的特徵和資訊。OOP 的這項原則稱為抽象。 OOP 中的抽像也可以定義為將現實世界問題的元素表示為程式中的物件的一種方式。抽象總是與有關物件或物件的屬性的某些資訊的概括相關聯,因此主要是在要解決的問題的背景下將重要資訊與無關緊要資訊分開。在這種情況下,可以有多個抽象層級。讓我們試著將抽象原則應用到我們的手機上。首先,讓我們重點介紹從最初到現在最常見的手機類型。例如,它們可以用圖 1 所示的圖表形式表示。 物件導向程式設計原理 - 2現在,借助抽象,我們可以突出顯示此對象層次結構中的一般信息:對象的常見抽象類型 - 電話、電話的一般特徵電話- 其創建年份和通用介面- 所有電話都能夠接聽和發送電話。在 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);
}
基於這個抽象類,我們將能夠使用其他基本的 Java OOP 原則在程式中建立新類型的手機,我們將在下面考慮。

封裝

在抽象的幫助下,我們突出顯示所有物件的共同點。然而,每款手機型號都是獨一無二的,並且與其他手機型號有所不同。我們如何在程序中劃定界限並指定這種個性?我們如何確保用戶不會意外或故意損壞我們的手機,或嘗試將一種型號轉換為另一種型號?對於真實物體的世界,答案是顯而易見的:你需要將所有部件放入手機機身中。畢竟,如果我們不這樣做,並將手機的所有內部和連接它們的電線留在外面,肯定會有好奇的實驗者想要「改進」我們手機的操作。為了避免對物件的設計和操作的這種幹擾,OOP使用了封裝原則——OOP的另一個基本原則,其中物件的屬性和行為被組合在一個類別中,物件的內部實作是隱藏的。用戶,並提供一個開放的介面來處理該物件。程式設計師的工作是確定哪些屬性和方法可以公開訪問,哪些是物件的內部實作並且不應修改。

封裝和存取控制

假設在生產過程中,有關它的資訊被刻在手機背面:其製造年份或製造商公司的徽標。這些資訊非常具體地描述了該模型的特徵——它的狀況。我們可以說,手機開發人員考慮到了這些資訊的不變性——不太可能有人會想到刪除雕刻。在 Java 世界中,未來物件的狀態是使用欄位在類別中描述的,並且它們的行為是使用方法來描述的。更改狀態和行為的能力是透過使用欄位和方法的存取修飾符 - privateprotectedpublicdefault(預設存取)來實現的。例如,我們決定創建年份、手機製造商的名稱以及其中一個方法屬於類別的內部實現,不能被程式中的其他物件更改。使用程式碼,該類別可以描述如下:
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("Дзынь-дзынь");
}

 }
修飾符private使類別的欄位和方法僅在該類別中可用。這意味著private不能從外部存取字段,也不能private呼叫方法。隱藏對方法的存取openConnection也使我們有機會自由更改該方法的內部實現,因為該方法保證不會被其他物件使用,也不會中斷它們的操作。為了使用我們的對象,我們call使用ring修飾符將方法保持開啟public提供用於處理物件的公共方法也是封裝機制的一部分,因為如果完全拒絕對物件的訪問,它將變得毫無用處。

遺產

我們再看一下手機圖表。您可以看到它代表了一個層次結構,其中位於下方的模型具有位於分支上的較高模型的所有特徵,以及它自己的特徵。例如,智慧型手機使用蜂窩網路進行通訊(具有手機的屬性),具有無線性和便攜性(具有無線電話的屬性),並且可以接聽和撥打電話(具有電話的屬性)。既然這樣,我們就可以談談物件屬性的繼承了。 在程式設計中,繼承是使用現有的類別來定義新的類別。 讓我們看一個使用繼承創建智慧型手機類別的範例。所有無線電話均由可充電電池供電,具有一定的使用壽命(以小時為單位)。因此,讓我們將此屬性新增到無線電話類別:
public abstract class WirelessPhone extends AbstractPhone {

    private int hour;

    public WirelessPhone(int year, int hour) {
        super(year);
        this.hour = hour;
    }
    }
手機繼承了無線電話的屬性,我們也在這個類別中加入了call和方法的實作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);
    }
}
最後是智慧型手機類別,與傳統手機不同,它擁有成熟的作業系統。您可以將該作業系統支援的新程式新增至您的智慧型手機,從而擴展其功能。使用程式碼,該類別可以描述如下:
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);
}

}
正如您所看到的,Smartphone我們創建了很少的新程式碼來描述該類,但我們得到了一個具有新功能的新類別。使用OOP繼承原理可以顯著減少程式碼量,從而使程式設計師的工作更加輕鬆。

多態性

如果我們觀察所有手機型號,那麼,儘管這些型號的外觀和設計存在差異,但我們可以識別它們的一些共同行為 - 它們都可以接聽和撥打電話,並且具有一組相當清晰和簡單的控制按鈕。應用我們已經知道的物件導向程式設計的基本原則之一,即程式設計術語中的抽象,我們可以說電話物件有一個公共介面。因此,手機使用者可以使用相同的控制按鈕(機械或觸控)輕鬆使用不同的型號,而無需了解裝置的技術細節。因此,您經常使用手機,並且可以輕鬆地透過固定電話撥打電話。OOP 中程式可以使用具有相同介面的物件而無需了解物件內部結構的資訊的原理稱為多態性。讓我們想像一下,在我們的程式中,我們需要描述一個可以使用任何電話型號呼叫另一個使用者的使用者。操作方法如下:
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);
    }
}
 }
現在讓我們來描述一下不同的手機型號。第一批手機型號之一:
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");
    }
}
普通固定電話:
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");
    }
}
最後,一個很酷的視訊電話:
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);
    }
  }
讓我們在方法中建立物件main()並測試該方法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
透過在物件上呼叫相同的方法user,我們得到了不同的結果。call方法內特定方法實現的選擇callAnotherUser是根據程式執行期間​​呼叫物件的特定類型動態進行的。這就是多態性的主要優點——程式執行過程中實現的選擇。在上面的電話類別範例中,我們使用了方法重寫,這是一種在不更改方法簽署的情況下更改基底類別中定義的方法實現的技術。這本質上是方法替換,程式運行時呼叫的是子類別中定義的新方法。通常,在重寫方法時,會使用註釋@Override,它告訴編譯器檢查被重寫和重寫方法的簽章。 因此,為了確保您的程序風格符合 OOP 概念和 OOP java 原則,請遵循以下提示:
  • 突出物體的主要特徵;
  • 建立物件時突出顯示公共屬性和行為並使用繼承;
  • 使用抽象類型來描述物件;
  • 嘗試始終隱藏與類別的內部實作相關的方法和欄位。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION