1. 程式人生 > >typeScript中的面向物件程式設計學習心得

typeScript中的面向物件程式設計學習心得

SOLID原則(設計模式的6大原則)

  • 單一職責原則(SRP):表明軟體元件(函式、類、模組)必須專注與單一的任務(只有單一的職責)
  • 開/閉原則(OCP):對擴充套件開放, 對修改關閉
  • 里氏替換原則(LSP):物件應該可以是在不改變程式正確性的前提下被它的子類所替換.
  • 介面隔離原則(ISP):應該將非常大的介面拆分成一些小的更具體的介面,多個特定特定客戶端介面要好於一個寬泛用途的介面
  • 依賴反轉原則(DIP):依賴於一個抽象而不是一個例項

​ 由屬性方法組成, 屬性通常用來描述物件的特徵, 方法通常用來描述物件的行為。

​ 其中有一個特殊的方法, 叫做構造方法(與java的構造方法一樣, 但是重寫構造方法有點麻煩),在通過new關鍵字建立一個類的例項的時候會被呼叫。

下面是一個簡單的例子, 定義了兩個類, 一個Person類和一個Email類

Person類: 三個屬性, 兩個方法

import {Email} from './email';
export class Person {
  public name : string;
  public surname : string;
  public email : Email;
  constructor(name, surname, email) {
    this.name = name;
    this.surname = surname;
    this.email = email;
  }
  greet() {
    alert('Hi');
  }
}

下面是Email類

export class Email {
  private email : string;
  constructor(email) {
    if (this.validateEamil(email)) {
      this.email = email;
    } else {
      throw new Error("invalid email!");
    }
  }
  private validateEamil(email) {
    let re = /\[email protected]\S+\.\S+/;
    return re.test(email);
  }
}

兩個類在檔案中的位置關係

在這裡插入圖片描述

這樣子寫是為了符合單一職責原則, 如果這樣寫不符合單一職責原則

export class Person {
  public name : string;
  public surname : string;
  public email : Email;
  constructor(name, surname, email) {
    this.name = name;
    this.surname = surname;
    if (this.validateEamil(email)) {
      this.email = email;
    } else {
      throw new Error("invalid email!");
    }
  }
  validateEamil(email) {
    let re = /\[email protected]\S+\.\S+/;
    return re.test(email);
  }
  greet() {
    alert('Hi');
  }
}

因為validateEamil方法是和Person類的行為並無關聯

繼承

​ 可以擴充套件已有的類,這個功能被稱為繼承,允許我們建立一個類(子類), 從已有的類(父類)上繼承所有的屬性和方法,子類還可以包含父類中沒有的屬性和方法。但是值得注意的是,一個子類只能繼承一個父類,不能繼承多個父類,沒有多重繼承。

可以看下面的一個例子, 還是用上面提到的Person類和Email類

Person類:

import {Email} from './email';
export class Person {
  public name : string;
  public surname : string;
  public email : Email;

  constructor(name: string, surname: string, email: Email) {
    this.name = name;
    this.surname = surname;
    this.email = email;
  }
  greet() {
    console.log('Hi');
  }
}

Email類:

export class Email {
  private email : string;
  constructor(email) {
    if (this.validateEamil(email)) {
      this.email = email;
    } else {
      throw new Error("invalid email!");
    }
  }
  private validateEamil(email) {
    let re = /\[email protected]\S+\.\S+/;
    return re.test(email);
  }
}

現在用Teacher類繼承Person類, Teacher類可以有父類沒有的屬性和方法, 也可以重寫父類已經有的方法

Teacher類:

import {Person} from './person';
import {Email} from './email';

export class Teacher extends Person{

  public subject: string[];

  constructor(name: string, surname: string, email: Email, subject: string[]) {
    super(name, surname, email);
    this.subject = subject;
  }

  greet() {
    super.greet();
    console.log('我教 ' + this.subject);
  }
  teach() {
    console.log('我是老師, 我教學生');
  }
}

也可以有一個類繼承Teacher類, 那麼這個類會繼承Teacher類中的所有方法和屬性, 也會繼承Person中的所有屬性和方法

import {Teacher} from './teacher';
import {Email} from './email';

export class SchoolPrincipal extends Teacher{

  constructor(name: string, surname: string, email: Email, subject: string[]) {
    super(name, surname, email, subject);
  }

}

//執行下面程式碼
    let schoolPrincipal = new SchoolPrincipal("name", "surname", email, ["name1", "name2"]);
    schoolPrincipal.greet();
    schoolPrincipal.teach();

但是這裡Person和Teacher都有greet()方法,當呼叫greet方法時,呼叫的是Teacher的greet方法,可以得出結論:

  • 父類(和父類的父類)有相同的方法的時候,呼叫直接繼承父類的方法