CodeGym /Java Blog /Toto sisi /面向對象的原則
John Squirrels
等級 41
San Francisco

面向對象的原則

在 Toto sisi 群組發布
Java 是一種面向對象的語言。這意味著您需要使用面向對象的範例來編寫 Java 程序。這個範例需要在你的程序中使用對象和類。讓我們嘗試通過示例來了解什麼是類和對象,以及如何在實踐中應用基本的 OOP 原則(抽象、繼承、多態和封裝)。

什麼是對象?

我們生活的世界是由物體組成的。環顧四周,我們可以看到我們被房屋、樹木、汽車、家具、餐具和電腦所包圍。所有這些東西都是對象,它們中的每一個都有一組特定的特徵、行為和目的。我們習慣於對象,我們總是將它們用於非常特定的目的。例如,如果我們需要上班,我們會開車。如果我們想吃東西,我們就用盤子。如果我們想休息,我們會找到一張舒適的沙發。人類習慣於從對象的角度來思考,以解決日常生活中的問題。這是在編程中使用對象的原因之一。這種方法稱為面向對象編程。讓我們舉個例子。想像一下,您已經開發出一款新手機並希望開始量產。作為手機的開發者,你知道它的用途,它是如何工作的,它的部件是什麼(機身、麥克風、揚聲器、電線、按鈕等)。更重要的是,只有您知道如何連接這些部件。但你不打算親自製作手機——你有一整隊工人來做這件事。為了避免重複解釋如何連接手機的部件,並確保所有手機都以相同的方式製造,在開始生產之前,您需要繪製一張描述手機如何組織的圖紙。在 OOP 中,我們將這樣的描述、繪圖、圖表或模板稱為類。它構成了程序運行時創建對象的基礎。類是對特定類型對象的描述——就像由字段、方法和構造函數組成的通用模板。對像是類的實例。

抽象

現在讓我們考慮如何從現實世界中的對象轉移到程序中的對象。我們將以電話為例。這種通信方式已有 100 多年的歷史。現代電話是一種比其 19 世紀的前輩複雜得多的設備。使用電話時,我們不會考慮它的結構和內部發生的過程。我們只需使用手機開發商提供的功能:按鈕或觸摸屏即可輸入電話號碼並撥打電話。最早的電話接口之一是需要旋轉才能打電話的曲柄。當然,這不是很方便。但它完美地完成了它的功能。如果你比較最現代的手機和最早的手機,您可以立即識別出對 19 世紀末的設備和現代智能手機最重要的功能。它們是撥打電話的能力和接聽電話的能力。事實上,這就是使電話成為電話的原因,而不是別的什麼。現在只是應用了一個OOP的原則:確定一個對象最重要的特徵和信息。這個原則被稱為抽象。在 OOP 中,抽像也可以定義為一種將現實世界任務的元素表示為程序中的對象的方法。抽象總是與對象的某些屬性的泛化相關聯,因此最主要的是在手頭任務的上下文中將有意義的信息與無關緊要的信息分開。此外,可以有多個抽象級別。讓' 讓我們嘗試將抽象原理應用到我們的手機上。首先,我們將確定最常見的手機類型——從最早的手機到現在的手機。例如,我們可以用圖 1 中的圖表形式表示它們。 面向對象的原則 - 2使用抽象,我們現在可以識別此對象層次結構中的一般信息:一般抽像對象(電話)、電話的共同特徵(例如,它的創建年份)和公共接口(所有電話都可以接聽和撥打電話)。這是它在 Java 中的樣子:

public abstract class AbstractPhone {
    private int year;

    public AbstractPhone(int year) {
        this.year = year;
    }
    public abstract void call(int outgoingNumber);
    public abstract void ring(int incomingNumber);
}
在一個程序中,我們可以使用這個抽像類並應用 OOP 的其他基本原則來創建新型​​電話,我們將在下面探討這些原則。

封裝

通過抽象,我們可以確定所有對象的共同點。但每種手機都是獨一無二的,在某種程度上與其他手機不同。在程序中,我們如何劃定界限並識別這種個性?我們如何做到這一點,以至於沒有人會意外或故意損壞我們的手機或嘗試將一種型號轉換為另一種型號?在現實世界中,答案很明顯:你需要把所有的零件都放在一個手機殼裡。畢竟,如果您不這樣做——而是將手機的所有內部部件和連接線留在外面——一些好奇的實驗者肯定會想要“改進”我們的手機。為了防止這種修補,在對象的設計和操作中使用了封裝原則。這個原則指出一個對象的屬性和行為被組合在一個單一的類中,對象' 其內部實現對用戶是隱藏的,並提供了一個公共接口來處理該對象。程序員的任務是確定對象的哪些屬性和方法應該可供公共訪問,哪些是應該不可訪問的內部實現細節。

封裝和訪問控制

假設有關手機的信息(其生產年份或製造商的徽標)在製造時刻在其背面。信息(其狀態)特定於此特定模型。我們可以說製造商確保此信息是不可更改的——任何人都不太可能想去除雕刻。在 Java 世界中,類使用字段描述未來對象的狀態,使用方法描述它們的行為。使用應用於字段和方法的修飾符控制對對象狀態和行為的訪問:私有、受保護、公共和默認。例如,我們決定生產年份、製造商名稱和其中一種方法是類的內部實現細節,不能被程序中的其他對象更改。在代碼中,

public class SomePhone {

    private int year;
    private String company;
    public SomePhone(int year, String company) {
        this.year = year;
        this.company = company;
    }
private void openConnection(){
    // findSwitch
    // openNewConnection...
}
public void call() {
    openConnection();
    System.out.println("Calling");
}

public void ring() {
    System.out.println("Ring-ring");
}

 }
private 修飾符允許類的字段和方法只能在此類中訪問。這意味著無法從外部訪問私有字段,因為無法調用私有方法。限制對openConnection方法的訪問還使我們能夠自由更改該方法的內部實現,因為該方法保證不會被其他對象使用或中斷其他對象的工作。為了使用我們的對象,我們使用 public 修飾符使callring方法可用。提供用於處理對象的公共方法也是封裝的一部分,因為如果訪問被完全拒絕,它將變得毫無用處。

遺產

讓我們再看一下電話圖。您可以看到它是一個層次結構,其中模型具有沿其分支位於較高位置的模型的所有功能,並添加了一些自己的功能。例如,智能手機使用蜂窩網絡進行通信(具有手機的屬性),無線便攜(具有無繩電話的屬性),可以接聽和撥打電話(具有電話的屬性)。我們在這裡擁有的是對象屬性的繼承。在編程中,繼承意味著使用現有的類來定義新的類。讓我們考慮一個使用繼承來創建智能手機類的示例。所有無繩電話均由可充電電池供電,具有一定的電池壽命。因此,我們將此屬性添加到無繩電話類中:

public abstract class CordlessPhone extends AbstractPhone {

    private int hour;

    public CordlessPhone (int year, int hour) {
        super(year);
        this.hour = hour;
    }
    }
手機繼承了無繩電話的屬性,我們在這個類中 實現了callring方法:

public class CellPhone extends CordlessPhone {
    public CellPhone(int year, int hour) {
        super(year, hour);
    }

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

    @Override
    public void ring(int incomingNumber) {
        System.out.println("Incoming call from " + incomingNumber);
    }
}
最後,我們有智能手機類,與傳統手機不同,它擁有成熟的操作系統。您可以通過添加可在其操作系統上運行的新程序來擴展智能手機的功能。在代碼中,該類可以描述如下:

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 的這一原則可以顯著減少所需的 Java 代碼量,從而使程序員的工作更輕鬆。

多態性

儘管各種電話的外觀和設計各不相同,但我們可以確定一些共同的行為:它們都可以接聽和撥打電話,並且都有一套相當清晰和簡單的控件。在編程方面,抽象原則(我們已經很熟悉了)讓我們可以說電話對像有一個共同的接口。這就是為什麼人們可以輕鬆使用具有相同控件(機械按鈕或觸摸屏)的不同型號的手機,而無需深入研究設備的技術細節。因此,您經常使用手機,並且可以輕鬆地從朋友的座機上撥打電話。OOP 的原理是說程序可以使用具有公共接口的對象而無需任何有關對象內部結構的信息,這稱為多態性。讓' 想像一下,我們需要我們的程序來描述可以使用任何電話呼叫另一個用戶的用戶。我們可以這樣做:

public class User {
    private String name;

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

    public void callAnotherUser(int number, AbstractPhone phone){
// And here's polymorphism: using the AbstractPhone type in the code!
        phone.call(number);
    }
}
 }
現在我們將描述幾種電話。最早的手機之一:

public class ThomasEdisonPhone extends AbstractPhone {

public ThomasEdisonPhone(int year) {
    super(year);
}
    @Override
    public void call(int outgoingNumber) {
        System.out.println("Crank the handle");
        System.out.println("What number would you like to connect to?");
    }

    @Override
    public void ring(int incomingNumber) {
        System.out.println("The phone is ringing");
    }
}
普通座機:

public class Phone extends AbstractPhone {

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

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

    @Override
    public void ring(int incomingNumber) {
        System.out.println("The phone is ringing");
    }
}
最後,一個很酷的視頻電話:

public class VideoPhone extends AbstractPhone {

    public VideoPhone(int year) {
        super(year);
    }
    @Override
    public void call(int outgoingNumber) {
        System.out.println("Connecting video call to " + outgoingNumber);
    }
    @Override
    public void ring(int incomingNumber) {
        System.out.println("Incoming video call from " + incomingNumber);
    }
  }
我們將在main()方法中創建對象並測試callAnotherUser()方法:

AbstractPhone firstPhone = new ThomasEdisonPhone(1879);
AbstractPhone phone = new Phone(1984);
AbstractPhone videoPhone=new VideoPhone(2018);
User user = new User("Jason");
user.callAnotherUser(224466, firstPhone);
// Crank the handle
// What number would you like to connect to?
user.callAnotherUser(224466, phone);
// Calling 224466
user.callAnotherUser(224466, videoPhone);
// Connecting video call to 224466
在用戶對像 上調用相同的方法會產生不同的結果。call方法的具體實現是在callAnotherUser()方法內部根據程序運行時傳入的具體對像類型動態選擇的。這是多態的主要優勢——在運行時選擇實現的能力。在上面給出的電話類示例中,我們使用了方法覆蓋——一種我們在不更改方法簽名的情況下更改基類中定義的方法的實現的技巧。這實質上取代了方法:在程序執行時調用子類中定義的新方法。通常,當我們重寫一個方法時,@Override使用註釋。它告訴編譯器檢查被覆蓋和覆蓋方法的簽名。最後,為確保您的 Java 程序符合 OOP 原則,請遵循以下提示:
  • 識別對象的主要特徵;
  • 識別公共屬性和行為並在創建類時使用繼承;
  • 使用抽像類型來描述對象;
  • 嘗試始終隱藏與類的內部實現相關的方法和字段。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION