封裝是將資料和函數捆綁到一個單元(即膠囊)中的過程,它還可以限制對某些資料/方法的存取。
它是 OOP 的四大支柱之一,其他三者分別是繼承、多態性和資料抽象。
採取盲目假設並在所有地方繼續使用封裝會更容易,但了解原因很重要,這樣您才能以正確的方式使用它。
讓我們試著透過查看範例任務來理解原因。
建構一個學生成績計算器,
方案一:非封裝方式
這個想法只是為了解決問題,所以我選擇了過程式設計實現它的方式,我相信它可以顯示出很好的對比並使問題看起來更明顯。
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 的問題:
這確實達到了預期的結果,但也存在一些與之相關的問題。僅舉幾例,
- 這裡的每個實作都是全域可存取的,並且未來貢獻者無法控制其使用。
- 資料和操作是分開的,因此很難追蹤哪些函數會影響資料。您必須仔細檢查每一段程式碼才能了解呼叫的內容以及執行的一部分。
- 隨著邏輯的擴展,函數變得更難管理。由於緊密耦合,更改可能會破壞不相關的程式碼。
透過合併封裝或執行以下兩個步驟使其更加明顯,
解決方案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());
注意上述解決方案,
2.數據學生與其每一個行為都捆綁在一起。
以上是物件導向程式設計—封裝的詳細內容。更多資訊請關注PHP中文網其他相關文章!