首頁 >web前端 >js教程 >物件導向程式設計—封裝

物件導向程式設計—封裝

Patricia Arquette
Patricia Arquette原創
2024-12-14 17:39:11729瀏覽

OOP - Encapsulation

什麼? ? ?

封裝是將資料和函數捆綁到一個單元(即膠囊)中的過程,它還可以限制對某些資料/方法的存取。

它是 OOP 的四大支柱之一,其他三者分別是繼承、多態性和資料抽象。

為什麼?

採取盲目假設並在所有地方繼續使用封裝會更容易,但了解原因很重要,這樣您才能以正確的方式使用它。

讓我們試著透過查看範例任務來理解原因。

任務:

建構一個學生成績計算器,

  • 計算平均分數
  • 確定學生是否失敗或通過
  • 如果任何主題標記無效( 100),則拋出錯誤

方案一:非封裝方式

這個想法只是為了解決問題,所以我選擇了過程式設計實現它的方式,我相信它可以顯示出很好的對比並使問題看起來更明顯。

type Subject = "english" | "maths";

interface IStudent {
  name: string;
  marks: Record<Subject, number>;
}

// Receive Input
const studentInput: IStudent = {
  name: "John",
  marks: {
    english: 100,
    maths: 100,
  },
};

// Step1: Validate the provided marks
Object.keys(studentInput.marks).forEach((subjectName) => {
  const mark = studentInput.marks[subjectName as Subject];
  if (mark > 100 || mark < 0) {
    throw new Error(`invlid mark found`);
  }
});

// Step2: find the total marks
const totalMarks = Object.keys(studentInput.marks).reduce(
  (accumulator: number, current: string) =>
    studentInput.marks[current as Subject] + accumulator,
  0
);

// Step3: find the average
const average = totalMarks / Object.keys(studentInput.marks).length;

// Step4: find the result
const boolResult = average > 40;

// Step 5: print result
console.log(boolResult);
console.log(average);

解決方案 1 的問題:

這確實達到了預期的結果,但也存在一些與之相關的問題。僅舉幾例,

  1. 這裡的每個實作都是全域可存取的,並且未來貢獻者無法控制其使用。
  2. 資料和操作是分開的,因此很難追蹤哪些函數會影響資料。您必須仔細檢查每一段程式碼才能了解呼叫的內容以及執行的一部分。
  3. 隨著邏輯的擴展,函數變得更難管理。由於緊密耦合,更改可能會破壞不相關的程式碼。

如何解決問題?

透過合併封裝或執行以下兩個步驟使其更加明顯,

  1. 對資料和功能的受控存取
  2. 將資料與行為捆綁

解決方案2:封裝方式

type SubjectNames = "english" | "maths";

interface IStudent {
  name: string;
  marks: Record<SubjectNames, number>;
}

class ResultCalculator {
  protected student: IStudent;
  constructor(student: IStudent) {
    this.student = student;
  }

  isPassed(): boolean {
    let resultStatus = true;
    Object.keys(this.student.marks).forEach((subject: string) => {
      if (this.student.marks[subject as SubjectNames] < 40) {
        resultStatus = false;
      }
    });
    return resultStatus;
  }

  getAverage(): number {
    this.validateMarks();
    return this.totalMarks() / this.subjectCount();
  }

  private validateMarks() {
    Object.keys(this.student.marks).forEach((subject: string) => {
      if (
        this.student.marks[subject as SubjectNames] < 0 ||
        this.student.marks[subject as SubjectNames] > 100
      ) {
        throw new Error(`invalid mark`);
      }
    });
  }

  private totalMarks() {
    return Object.keys(this.student.marks).reduce(
      (acc, curr) => this.student.marks[curr as SubjectNames] + acc,
      0
    );
  }

  private subjectCount() {
    return Object.keys(this.student.marks).length;
  }
}

// Receive Input
const a: IStudent = {
  name: "jingleheimer schmidt",
  marks: {
    english: 100,
    maths: 100,
  },
};

// Create an encapsulated object
const result = new ResultCalculator(a);

// Perform operations & print results
console.log(result.isPassed());
console.log(result.getAverage());

注意上述解決方案,

  1. 方法totalMarks、subjectCount、validateMarks 和成員變數student 不公開,只能由類別物件使用。

2.數據學生與其每一個行為都捆綁在一起。

以上是物件導向程式設計—封裝的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn