LoginSignup
3
3

More than 3 years have passed since last update.

typescript ポリモーフィズム

Last updated at Posted at 2020-10-04

ポリモーフィズムを使う場合と使わない場合を例に、
typescriptでポリモーフィズムを使う方法を紹介します。
学校クラスのメソッド内で生徒クラスと先生クラスのパラメータを使うメソッドを使って説明します。

ポリモーフィズムを使わない場合

1.悪いデザインパターン

schoolクラスにstudentClaimとteacherClaimを実装しています。
これだと、新しいクラスが増える度に、新たにxxxClaimというメソッドを実装する必要があります。

index.ts
class Student {
  constructor(public name: string, public age: number) {}
}

class Teacher {
  constructor(public name: string, public age: number) {}
}

class School {
  studentClaim(student: Student): string {
    return `I am a student. name: ${student.name}, age: ${student.age}`
  }

  teacherClaim(teacher: Teacher): string {
    return `I am a teacher. name: ${teacher.name}, age: ${teacher.age}`
  }
}

const student = new Student('tatsumi', 16)
const teacher = new Teacher('ogawa', 47)

const school = new School()
console.log(school.studentClaim(student))
console.log(school.teacherClaim(teacher))
// => I am a student. name: tatsumi, age: 16
// => I am a teacher. name: ogawa, age: 47

2.良いデザインパターン

schoolクラスのclaimメソッドの引数にStudentクラスかTeacherクラスが渡るように設定しました。
この方法だと、悪いデザインパターンで説明したように、新しいクラスが増えても新たにxxxClaimというメソッドを実装する必要はなくなりました。

index.ts
class Student {
  constructor(public name: string, public age: number) {}
  claim() {
    return `I am a student. name: ${this.name}, age: ${this.age}`
  }
}

class Teacher {
  constructor(public name: string, public age: number) {}
  claim() {
    return `I am a teacher. name: ${this.name}, age: ${this.age}`
  }
}

class School {
  claim(roleable: Student | Teacher): string {
    return roleable.claim()
  }
}

const student = new Student('tatsumi', 16)
const teacher = new Teacher('ogawa', 47)

const school = new School()
console.log(school.claim(student))
console.log(school.claim(teacher))
// => I am a student. name: tatsumi, age: 16
// => I am a teacher. name: ogawa, age: 47

しかし、まだ問題は残っています。
新しいクラスが増えた場合にclaimメソッドの引数を更新する必要があります。
例えば、committeeクラスを新たに実装した場合、claimメソッドの引数を
claim(roleable: Student | Teacher | Committee)に更新する必要があります。
つまり、新しいクラスを追加する度に既存のclaimメソッドを更新する必要があるということです。
これでは、今後修正が加わる度に、保守やテストが大変になっていきます。

ポリモーフィズムを使う場合

ポリモーフィズムを使わない場合で説明した問題を解決するために、インターフェイスを使います。
claimメソッドの引数の型をroleインターフェイスに変更することで、roleインターフェイスのメンバ(name, age, claim())を満たすクラスを引数に渡すことができます。
これで、新たにクラスを追加してもそのクラスがroleインターフェイスのメンバを満たしている限り、schoolクラスのclaimメソッドを修正する必要はありません。

index.ts
interface Role {
  name: string
  age: number
  claim(): string
}

class Student {
  constructor(public name: string, public age: number) {}
  claim() {
    return `I am a student. name: ${this.name}, age: ${this.age}`
  }
}

class Teacher {
  constructor(public name: string, public age: number) {}
  claim() {
    return `I am a teacher. name: ${this.name}, age: ${this.age}`
  }
}

class School {
  claim(roleable: Role): string {
    return roleable.claim()
  }
}

const student = new Student('tatsumi', 16)
const teacher = new Teacher('ogawa', 47)

const school = new School()
console.log(school.claim(student))
console.log(school.claim(teacher))
// => I am a student. name: tatsumi, age: 16
// => I am a teacher. name: ogawa, age: 47

おまけ

ポリモーフィックを使って、新たにcommitteeクラスを追加した場合は以下のようになります。

index.ts
interface Role {
  name: string
  age: number
  claim(): string
}

class Student {
  constructor(public name: string, public age: number) {}
  claim() {
    return `I am a student. name: ${this.name}, age: ${this.age}`
  }
}

class Teacher {
  constructor(public name: string, public age: number) {}
  claim() {
    return `I am a teacher. name: ${this.name}, age: ${this.age}`
  }
}

class Committee {
  constructor(public name: string, public age: number) {}
  claim() {
    return `I am a commitee. name: ${this.name}, age: ${this.age}`
  }
}

class School {
  claim(roleable: Role): string {
    return roleable.claim()
  }
}

const student = new Student('tatsumi', 16)
const teacher = new Teacher('ogawa', 47)
const committee = new Committee('ito', 40)

const school = new School()
console.log(school.claim(student))
console.log(school.claim(teacher))
console.log(school.claim(committee))
// => I am a student. name: tatsumi, age: 16
// => I am a teacher. name: ogawa, age: 47
// => I am a commitee. name: ito, age: 40
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3