iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0
自我挑戰組

用ChatGPT詠唱來完成工作與點亮前後端技能樹系列 第 11

【Day11】ChatGPT請教教我:Class(類別) ! Object (物件)!物件導向 OOP!

  • 分享至 

  • xImage
  •  

目前這個系列已挑選ChatGPT、前端&React相關章節出版成書!
感謝大家的閱讀與支持!
《用 ChatGPT 詠唱來點亮 React & 前端技能樹》
歷經重新整理、校正、編排、與修改後,讓章節內容之間的銜接更平順,除了補充上更多的解說之外,甚至有部分章節為重新撰寫的內容,讓理解變得更輕鬆!
目前已在天瓏書局博客來金石堂等通路都買得到了! 也有電子書的選擇!
歡迎各位點擊連結選購,謝謝大家~
https://ithelp.ithome.com.tw/upload/images/20240419/20135750lQM12by6v1.jpg


從這個章節開始,遇到有關JS (JavaScript)的內容,我會預設改用TS (TypeScript)來寫
向ChatGPT提問的自定指示中,也會改成這樣
https://ithelp.ithome.com.tw/upload/images/20230920/20135750s3h6rpaN0A.png

有TypeScript相關問題,請看我的上一篇介紹:
【Day10】ChatGPT請教教我:TypeScript!Enum!泛型 !

沒問題就Go Go了!

Class是什麼

有關class相關的用法,即使是資工本科生,在學習的時候也有可能會遇到一些困難
讓我們看看ChatGPT是如何介紹Class的
https://ithelp.ithome.com.tw/upload/images/20230920/20135750iqSsYs1mgR.png

當然可以!我會用簡單易懂的方式來介紹什麼是 class。

什麼是 Class?

在程式設計中,class(類別)是一種用來創建物件(object)的藍圖或模板。它定義了一個物件的特性(屬性)和行為(方法),可以看作是封裝了資料和相關操作的容器。

舉例來說,假設我們要描述一個狗的類型,它會有一些特性,如名字、品種、年齡等,同時也會有一些行為,比如吠叫、奔跑等。這些特性和行為可以被封裝在一個狗的類別中。

Class 的基本結構

以下是一個 TypeScript 中的 class 的基本結構範例:

class Dog {
  // 屬性
  name: string;
  breed: string;
  age: number;

  // 建構子
  constructor(name: string, breed: string, age: number) {
    this.name = name;
    this.breed = breed;
    this.age = age;
  }

  // 方法
  bark() {
    console.log(`${this.name}在叫!`);
  }

  run() {
    console.log(`${this.name}在奔跑!`);
  }
}

如何使用 Class?

要使用這個狗的類別,你可以這樣做:

// 創建一個狗的物件
const myDog = new Dog("旺財", "柴犬", 3);

// 存取屬性或呼叫方法
console.log(`我家狗狗的品種是${myDog.breed}`);
myDog.bark();
myDog.run();

這樣,你就可以使用這個狗的類別來創建不同的狗物件,並且存取它們的特性和行為。

這只是 class 的基本概念,還有許多進階的用法和概念,但希望這個簡單的介紹對你有幫助!如果你有任何問題或需要進一步的解釋,請隨時告訴我。

上面提供了語法,但卻不知道什麼時候會需要用到class
或是常見使用情境是什麼

所以來問問看ChatGPT
https://ithelp.ithome.com.tw/upload/images/20230920/20135750LGPz0opose.png

Class 在程式設計中有著重要的作用,它的常見用途包括以下幾個方面:

  1. 物件導向程式設計(Object-Oriented Programming, OOP):Class 是物件導向程式設計的基礎。它可以幫助程式設計師將資料和相關操作封裝在一個單元中,使得程式碼更具結構性和模組化。
  2. 模組化開發:透過 class,可以將相關的資料和功能組織成一個模組,這樣可以方便管理和維護程式碼。
  3. 程式碼重複使用:你可以根據 class 創建多個物件,這些物件會共享相同的特性和行為,從而節省了重複編寫相似程式碼的工作量。
  4. 抽象化和封裝:Class 允許你將特定的實現細節隱藏起來,只向外部提供必要的接口,這樣可以降低程式的複雜度,提高代碼的可讀性。
  5. 繼承:Class 可以透過繼承機制,讓一個 class 繼承另一個 class 的特性和行為,進一步提高程式碼的重用性。
  6. 多型:Class 的繼承和多型機制讓你可以針對不同類型的物件,使用相同的介面進行操作,這樣可以撰寫更通用和靈活的程式碼。

總的來說,Class 是一個強大的程式設計工具,它可以幫助你組織和管理程式碼,使得程式更容易理解、維護和擴展。在前端開發中,Class 常被用來建構 UI 元件、管理狀態、定義資料模型等等。因此,對於你作為一名前端工程師的目標來說,熟練掌握 Class 將是非常重要的一環。

講了很多新的專有名詞,講了許多好處
但沒有範例還是有點難懂,但得到了很多新關鍵字

先請他直接針對各點再解釋並給予範例吧
https://ithelp.ithome.com.tw/upload/images/20230920/20135750Jz7nVPGEDs.png

好的,我會針對以上提到的各點,提供相應的範例和詳細解釋。

1. 物件導向程式設計(OOP)

物件導向程式設計是一種程式設計範式,它將程式中的資料和相關操作封裝在一個物件中。

範例:

class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  introduce() {
    console.log(`我叫${this.name},今年${this.age}歲。`);
  }
}

const john = new Person("John", 30);
john.introduce(); // 輸出:我叫John,今年30歲。

這裡我們定義了一個 Person 的 class,它有 nameage 兩個屬性,以及一個 introduce 方法,用來介紹自己。通過 new Person(...) 我們可以創建一個 Person 的物件。

2. 模組化開發

Class 可以幫助我們將相關的資料和功能組織成一個模組,使得程式碼更易於管理。

範例:

// person.ts
class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  introduce() {
    console.log(`我叫${this.name},今年${this.age}歲。`);
  }
}

export default Person;

// main.ts
import Person from './person';

const john = new Person("John", 30);
john.introduce(); // 輸出:我叫John,今年30歲。

這裡我們將 Person 的 class 定義在 person.ts 檔案中,然後在 main.ts 中引入並使用它。這樣可以使得程式碼更模組化,方便維護。

3. 程式碼重複使用

透過 class,我們可以創建多個物件,這些物件共享相同的特性和行為。

範例:

class Circle {
  radius: number;

  constructor(radius: number) {
    this.radius = radius;
  }

  getArea() {
    return Math.PI * this.radius ** 2;
  }
}

const circle1 = new Circle(5);
const circle2 = new Circle(8);

console.log(circle1.getArea()); // 輸出:78.54
console.log(circle2.getArea()); // 輸出:201.06

在這個例子中,我們創建了兩個不同半徑的圓形物件 circle1circle2,它們都擁有相同的 getArea 方法,但返回的面積值會根據半徑而變化。

4. 抽象化和封裝

Class 允許你將特定的實現細節隱藏起來,只向外部提供必要的接口。

範例:

class BankAccount {
  private balance: number = 0;

  deposit(amount: number) {
    this.balance += amount;
  }

  withdraw(amount: number) {
    if (amount <= this.balance) {
      this.balance -= amount;
    } else {
      console.log("餘額不足!");
    }
  }

  getBalance() {
    return this.balance;
  }
}

const account = new BankAccount();
account.deposit(1000);
account.withdraw(500);
console.log(account.getBalance()); // 輸出:500

在這個例子中,我們定義了一個 BankAccount 的 class,它有一個私有的 balance 屬性,以及 depositwithdrawgetBalance 方法來操作和獲取帳戶餘額。這樣可以隱藏 balance 的實際實現細節。

這是一些 class 的基本用法範例,希望這些範例能幫助你更好地理解 class 的各種作用和用途。如果有任何問題,請隨時告訴我!

可以看到他每一項都給予範例了
其中提到了一個關鍵的專有名詞:物件導向程式設計(OOP)
https://ithelp.ithome.com.tw/upload/images/20230920/20135750SGPpnwmtYh.png

物件導向程式設計(Object-Oriented Programming, OOP)是一種程式設計範式,它以"物件"(object)為基礎,將資料和相關操作封裝在一個單元中,透過這種方式來組織和管理程式碼。

在 OOP 中,每個物件都是類別(class)的一個實例。類別是一種藍圖或模板,它定義了一個物件的特性(屬性)和行為(方法)。屬性代表物件的狀態或特徵,而方法則定義了物件可以進行的操作或行為。

以下是一個簡單的物件導向程式設計的範例:

class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  introduce() {
    console.log(`我叫${this.name},今年${this.age}歲。`);
  }
}

const john = new Person("John", 30);
john.introduce(); // 輸出:我叫John,今年30歲。

在這個例子中,我們定義了一個 Person 的 class,它有 nameage 兩個屬性,以及一個 introduce 方法,用來介紹自己。透過 new Person(...) 我們創建了一個 Person 的物件 john

OOP 的核心概念:

  1. 封裝(Encapsulation):將相關的資料和功能封裝在一個類別中,並對外部隱藏實現細節。
  2. 繼承(Inheritance):允許一個類別繼承另一個類別的特性和行為,可以重用現有的程式碼。
  3. 多型(Polymorphism):允許相同的介面用於不同的數據類型或物件,使得程式碼更靈活和通用。

如何學習 OOP?

步驟 1: 了解基本概念

首先,你需要理解封裝、繼承和多型這三個基本的 OOP 概念。

步驟 2: 熟悉類別和物件的建立

學會如何定義類別,並且創建類別的物件。

步驟 3: 學習封裝和存取控制

了解如何使用封裝來隱藏物件的實現細節,以及如何設定不同的存取控制(public、private、protected)。

步驟 4: 掌握繼承和多型

學習如何使用繼承來建立物件之間的階層關係,並了解多型如何使得相同的介面可以應用在不同的物件上。

步驟 5: 實際應用

將所學應用到實際的程式開發中,建立自己的物件和類別,並逐漸熟練 OOP 的技巧。

步驟 6: 閱讀相關資源和範例

閱讀相關的書籍、教學文章,並參考各種範例,進一步加深對 OOP 的理解和應用。

總的來說,學習 OOP 需要不斷的練習和實踐,隨著時間的推移,你將會變得更加熟練和自信。如果你有任何具體的問題或需要進一步的解釋,請隨時告訴我!

https://ithelp.ithome.com.tw/upload/images/20230920/201357503w3C3ssIuU.png

當然,讓我詳細解釋物件導向程式設計(OOP)的核心概念:

1. 封裝(Encapsulation):

封裝是指將相關的資料和行為(方法)封裝在一個單位(類別)中,並對外部隱藏內部的實現細節,僅向外提供必要的介面。這樣做的目的是為了降低系統的複雜度,提高程式碼的可讀性和可維護性。

範例:

class BankAccount {
  private balance: number = 0;

  deposit(amount: number) {
    this.balance += amount;
  }

  withdraw(amount: number) {
    if (amount <= this.balance) {
      this.balance -= amount;
    } else {
      console.log("餘額不足!");
    }
  }

  getBalance() {
    return this.balance;
  }
}

在這個例子中,balance 是一個私有屬性,只能在 BankAccount 內部訪問。外部無法直接存取 balance,只能透過 depositwithdrawgetBalance 方法來進行操作。

2. 繼承(Inheritance):

繼承是指一個類別(子類別)可以繼承另一個類別(父類別)的特性和行為。子類別可以使用父類別的屬性和方法,並且可以擴展或修改它們,同時也可以新增自己的屬性和方法。

範例:

class Animal {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  makeSound() {
    console.log("動物發出聲音。");
  }
}

class Dog extends Animal {
  bark() {
    console.log("狗狗在叫!");
  }
}

const myDog = new Dog("旺財");
myDog.makeSound(); // 輸出:動物發出聲音。
myDog.bark(); // 輸出:狗狗在叫!

在這個例子中,Dog 類別繼承了 Animal 類別,因此它可以使用 name 屬性和 makeSound 方法。同時,Dog 類別也新增了自己的方法 bark

3. 多型(Polymorphism):

多型是指相同的介面可以應用在不同的物件上,這樣可以提高程式的靈活性和通用性。在多型中,不同的類別可以實現相同的介面或抽象類別,但具體的實現方式可以各自不同。

範例:

class Shape {
  calculateArea(): number {
    return 0;
  }
}

class Circle extends Shape {
  radius: number;

  constructor(radius: number) {
    super();
    this.radius = radius;
  }

  calculateArea(): number {
    return Math.PI * this.radius ** 2;
  }
}

class Rectangle extends Shape {
  width: number;
  height: number;

  constructor(width: number, height: number) {
    super();
    this.width = width;
    this.height = height;
  }

  calculateArea(): number {
    return this.width * this.height;
  }
}

const circle = new Circle(5);
const rectangle = new Rectangle(4, 6);

console.log(circle.calculateArea()); // 輸出:78.54
console.log(rectangle.calculateArea()); // 輸出:24

在這個例子中,Shape 是一個抽象類別,它定義了一個計算面積的方法。CircleRectangle 類別都繼承了 Shape 並實現了 calculateArea 方法,但實現的方式各自不同,這就是多型的一個例子。

這就是物件導向程式設計的核心概念:封裝、繼承和多型。透過這些概念,我們可以建立更為結構化、靈活且可維護的程式碼。如果你有任何進一步的問題或需要更詳細的解釋,請隨時告訴我!

前面在講述跟「封裝」有關的議題時,都會用到一個新的關鍵字: private
更前面講解要如何學習物件導向時,也有提到「存取控制(public、private、protected)」等

因此繼續拿關鍵字來深入詢問ChatGPT

https://ithelp.ithome.com.tw/upload/images/20230920/20135750MreStIAejE.png

當然,讓我來進一步深入講解如何設定不同的存取控制(public、private、protected):

存取修飾符:

在 TypeScript 中,可以使用存取修飾符來指定類別的成員(屬性和方法)的存取範圍,這有助於控制對類別內部資料的訪問權限。

1. public

public 表示成員可以在類別內部和外部被訪問。這是預設的存取修飾符,如果未指定存取修飾符,則默認為 public

範例:

class Person {
  public name: string;

  constructor(name: string) {
    this.name = name;
  }

  public introduce() {
    console.log(`我叫${this.name}。`);
  }
}

const john = new Person("John");
console.log(john.name); // 可以訪問
john.introduce(); // 可以呼叫

2. private

private 表示成員僅在類別內部可以被訪問,外部無法訪問。

範例:

class BankAccount {
  private balance: number = 0;

  deposit(amount: number) {
    this.balance += amount;
  }

  getBalance() {
    return this.balance;
  }
}

const account = new BankAccount();
account.deposit(1000); // 可以呼叫
console.log(account.balance); // 無法訪問,因為是 private

3. protected

protected 表示成員可以在類別內部以及子類別中被訪問,但無法在外部訪問。

範例:

class Animal {
  protected sound: string;

  constructor(sound: string) {
    this.sound = sound;
  }

  makeSound() {
    console.log(this.sound);
  }
}

class Dog extends Animal {
  bark() {
    console.log(`${this.sound} ${this.sound}!`);
  }
}

const dog = new Dog("汪汪");
dog.makeSound(); // 可以呼叫
dog.bark(); // 可以呼叫
console.log(dog.sound); // 無法訪問,因為是 protected

使用情境:

  • 使用 public 當你希望該成員可以在類別內外被訪問時。
  • 使用 private 當你希望限制該成員僅在類別內部被訪問時。
  • 使用 protected 當你希望該成員可以在類別內部以及子類別中被訪問時。

存取修飾符可以幫助你有效地控制類別成員的訪問範圍,以保護資料的安全性和提高程式碼的可維護性。當你在設計類別時,請根據需求合理地選擇適當的存取修飾符。如果有任何進一步的問題或需要更詳細的解釋,請隨時告訴我!

OK,上面講這麼多,也講了一堆優點
像是結構化、靈活、可維護之類的

但我認為人類是一種不見棺材不掉淚,沒有痛過無法痛改前非的物種(?)
所以來請他提供一下,如果不使用class的話
到底會有什麼問題,請他提供對照
https://ithelp.ithome.com.tw/upload/images/20230920/20135750JknFOjeIYs.png

如果不使用物件導向的概念來撰寫程式,會導致程式碼難以維護、擴展和理解,也會增加程式碼的複雜度。以下我會透過範例來比較使用和不使用物件導向的情況。

1. 沒有使用物件導向的情況:

範例:

let person1Name = "John";
let person1Age = 30;

let person2Name = "Jane";
let person2Age = 25;

function introducePerson1() {
  console.log(`我叫${person1Name},今年${person1Age}歲。`);
}

function introducePerson2() {
  console.log(`我叫${person2Name},今年${person2Age}歲。`);
}

introducePerson1(); // 輸出:我叫John,今年30歲。
introducePerson2(); // 輸出:我叫Jane,今年25歲。

2. 使用物件導向的情況:

範例:

class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  introduce() {
    console.log(`我叫${this.name},今年${this.age}歲。`);
  }
}

const person1 = new Person("John", 30);
const person2 = new Person("Jane", 25);

person1.introduce(); // 輸出:我叫John,今年30歲。
person2.introduce(); // 輸出:我叫Jane,今年25歲。

問題與比較:

  1. 可維護性:在第一個範例中,當我們想要新增更多的人員時,必須手動添加變數和函數,這樣會使得程式碼變得雜亂且難以維護。在第二個範例中,我們可以輕鬆地創建新的 Person 物件,使得程式碼更具結構性和維護性。
  2. 可擴展性:在第一個範例中,如果我們想要為每個人員添加更多的資訊(例如地址、電話等),則必須修改相應的變數和函數。在第二個範例中,我們只需在 Person 類別中新增屬性和方法即可。
  3. 程式碼重複使用:在第一個範例中,每個函數都是針對特定的人員,無法複用。在第二個範例中,我們可以創建多個 Person 物件,它們共享相同的 introduce 方法。
  4. 程式碼結構:使用物件導向的方式可以使程式碼更有結構性和模組化,使得每個元件的職責更加清晰明確。

總的來說,物件導向的概念使得程式碼更易於維護、擴展和理解,並且提高了程式碼的重複使用性。因此,在較大型的專案或需要長期維護的情況下,使用物件導向是非常重要的。

結語

OK以上就是我們拿Class相關的概念來詢問ChatGPT的結果
對話紀錄放在這邊:https://chat.openai.com/share/ef51f0a2-014c-483d-999c-6a90baff7cae

我認為物件導向本身就不是一個好懂的概念
可能要實際在撰寫程式著碰到痛點,才知道物件導向的好處
我自己大學時花了一整個學期來學習物件導向,當時仍然沒有很融會貫通

直到工作實際碰到痛點,才開始把以前學過的東西重新撿回來
花了大量時間重新學習,把程式碼重構整理成有使用物件導向的模式

痾,對。我入職的時候裡面的程式碼沒有在跟你物件導向的
所有的變數就這樣全域零散在各處,超過二十個以上零散的變數你能想像嗎

希望以上的範例與教學可以幫助到正在學習物件導向的各位

我是物件導向信徒的前端工程師一宵三筵,我們明天見~


上一篇
【Day10】ChatGPT請教教我:TypeScript!Enum!泛型 !
下一篇
【Day12】ChatGPT請教教我:Command Line - 基礎CMD指令、Terminal指令
系列文
用ChatGPT詠唱來完成工作與點亮前後端技能樹56
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言