Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

2 • 株式会社オンラインコンサルタント 代表取締役 • プログラミング歴は16年 • 受託開発・自社サービスなど多数の開発 • メインの実績は3000社以上の導入実績がある 「ODIN リアルタイム配送システム」 という配送会社向けのシステム https://delivery-system.com/ @Akiko_Goto999

Slide 3

Slide 3 text

3 • プログラミングを始めて2,3年以上 • オブジェクト指向でプログラミングをしている • オブジェクト指向のプログラミングを理解はでき るし、自分で書いているが、うまく書けているか 自信がない

Slide 4

Slide 4 text

4

Slide 5

Slide 5 text

5 さる チンパンジー ねこ さる チンパンジー ねこ 運動能 力 100~200 80~180 300~400 知能 150~200 200~300 50 鳴き声 ウキー ウキー ニャー

Slide 6

Slide 6 text

6 抽象スーパークラス 動物 (Animal) カッコ内はクラス名 抽象スーパークラス 猿 (Ape) クラス 猿 (Monkey) クラス チンパンジー (Chimpanzee) クラス 猫 (Cat) 簡単っす! 白河くん 発田くん 中条さん 若手プログラマーの皆さん(仮想のキャラクターです)

Slide 7

Slide 7 text

7 abstract class Animal { name : string intelligence : number exercise_ability: number constructor(name: string, intelligence: number, exercise_ablility: number) { this.name = name; this.intelligence = intelligence; this.exercise_ability = exercise_ablility; } abstract bark(): void } abstract class Ape extends Animal { bark(): void { console.log('ウキー') } } class Monkey extends Ape { } //CatクラスとChimpanzeeクラスは省略 コードはTypeScriptで書いていきます。

Slide 8

Slide 8 text

8 さる チンパンジー ねこ さる チンパンジー ねこ 運動能 力 100~200 80~180 300~400 知能 150~200 200~300 50 鳴き声 ウキー ウキー ニャー 高所から落ちたとき 運動能力が150以上の動物は 空中で1回転できる 知能が180以上の動物は 絵を描くことができる

Slide 9

Slide 9 text

9

Slide 10

Slide 10 text

10 最初のクラス設計は保 ちながら、インスタンス 化するコントローラーで 判定をします! 白河くん (仮想のキャラクターと仮想の回答例です。) 高所から落ちたとき 運動能力が150以上の動物は 空中で1回転できる 知能が180以上の動物は 絵を描くことができる 実装したい機能 抽象スーパークラス 動物 (Animal) カッコ内はクラス名 抽象スーパークラス 猿 (Ape) クラス 猿 (Monkey) クラス チンパンジー (Chimpanzee) クラス 猫 (Cat)

Slide 11

Slide 11 text

11 abstract class Animal { name : string intelligence : number exercise_ability: number //コンストラクタはP5と同様なので省略 abstract bark(): void draw(): void { console.log('絵を描いたよ') } } // MonkeyクラスとChimpanzeeクラスはP5と同様なので省略 const animal1 = new Monkey('エテ吉', 180, 180) const animal2 = new Chimpanzee('ジョージ', 250, 90) if(animal1.intelligence >= 180) { animal1.draw() } 白河くん

Slide 12

Slide 12 text

12 高所から落ちたとき 運動能力が150以上の動物は 空中で1回転できる 知能が180以上の動物は 絵を描くことができる 実装したい機能 そしたら4足歩行動物というインター フェースを作って、空中で一回転できる とか、絵を描けるとかはインターフェー スに実装します。 インターフェースにした方がテストも書 きやすいし実装が軽くてよいとよく聞き ます。 quadrupedal animals インターフェース 発田くん クラス 猿 (Monkey) クラス チンパンジー (Chimpanzee) クラス 猫 (Cat)

Slide 13

Slide 13 text

13 発田くん class Chimpanzee implements QuadrupedalAnimals { // プロパティ、コンストラクタは省略 isDrawable(): boolean { if(this.intelligence >= 180) { return true; } return false; } isSpinable(): boolean { if(this.exercise_ability >= 150) { return true; } return false; } spin() { } draw() { console.log('絵を描いたよ') } } interface QuadrupedalAnimals{ name: string exercise_ability: number isSpinable():boolean spin():void isDrawable():boolean draw():void } const animal = new Chimpanzee('ジョージ', 250, 100) if(animal.isDrawable()){ animal.draw() }

Slide 14

Slide 14 text

14 猿は絵を描くことができる猿もいる、 しかし猫はどんな猫でも 絵を描くことができない。 現実では当たり前のことなので、 それらをコードに落とし込みます。 それがDDDだと思います。 中条さん (仮想のキャラクターと仮想の回答例です。) 高所から落ちたとき 運動能力が150以上の動物は 空中で1回転できる 知能が180以上の動物は 絵を描くことができる 実装したい機能 抽象スーパークラス 動物 (Animal) 抽象スーパークラス 猿 (Ape) クラス 猿 (Monkey) クラス チンパンジー (Chimpanzee) クラス 猫 (Cat)

Slide 15

Slide 15 text

15 中条さん export abstract class Ape extends Animal { bark(): void { console.log('ウキ-') } fall(): void { if (this.exercise_ability > 150) { this.turn_around() } else { this.fall_down() } } abstract turn_around(): void abstract fall_down(): void } export class Cat extends Animal { bark(): void { console.log('ニャー') } draw(): void { throw new Error('猫は絵が描けません') } fall(): void { this.turn_around() } turn_around(): void { console.log('1回転して華麗に着地') } } export class Chimpanzee extends Ape { private readonly items: string[] = [] constructor(name: string, intelligence: number, exercise_ablility: number) { super(name, intelligence, exercise_ablility) this.items.push('バナナ', '木の実', '昆虫') } draw(): void { console.log('絵が描けます。') } turn_around(): void { console.log('1回転して華麗に着地') } fall_down(): void { console.log('ドサッと落ちる') } }

Slide 16

Slide 16 text

16 そんなこと言っても、 オブジェクト指向の例はいつも 哺乳類とか出てきますが、 現実のプログラミングの現場 では哺乳類とかを 扱わないんですよ!

Slide 17

Slide 17 text

17 車を100台以上保有していますが、車検・保険・メンテナンス などの管理がとても煩雑です。 今は、地方の営業所ごとにExcelで担当者が管理しています が、効率が悪いのでシステムを作って効率化したいのです。 車検・保険が切れないようにしたいので、車検や保険が切れ る前に担当者へメールで通知してほしいんですよね。そのタ イミングは、車検は半年前と3か月前と1か月前、保険類は3 か月前とかがよいです。 また、車両のメンテナンスについては車検以外に定期点検と 言って車の種類ごとに、3か月単位や6か月単位で行う点検 があります。 その点検を怠らないように、これも点検の3日前にはメールで 担当者に通知を行いたいです。 保険については、とりあえず、自賠責保険と任意保険の2種 類でよいです。保険は、事故の際に緊急連絡先がすぐ取り出 せるようにしたいですね。他にも… 顧客

Slide 18

Slide 18 text

18 保険や車検・定期点検の切れる前に それぞれのタイミングでメール通知 保険は緊急連絡先がすぐ取り出せる ようにしたい 実装したい機能 車検は半年前・3か月前 1か月前にメール通知 決まった実装内容 ・毎日定時にプログラムを走らせて、そ の時間はメール通知が必要な時間か調 べる ・一旦メール通知したら、次の通知タイミ ングをDBに格納しておく ・タイミングは日付で管理 (本来はUnixTimeなどの方がよいが、サ ンプルコードの可読性のため日付) ・DBへの読み書きは既存の機能で存在 するので必要ない ・車検の有効期限などは別のプログラ ムで更新されるので今回は実装しなくて よい

Slide 19

Slide 19 text

19 export class NotifierForInspectionAndInsurance { private category: string private email: string private expire_date: string private notify_timing: string private emergency_contact?: string | undefined constructor(category: string, email: string, expire_date: string, notify_timing: string, emergency_contact?: string) { this.category = category this.email = email this.expire_date = expire_date this.notify_timing = notify_timing this.emergency_contact = emergency_contact } notify(): void { this.sendEmail(this.email, '通知処理') this.setNextNotifyTiming() } isNotifyTiming(): boolean { const currentDate = this.formatDateToYYYYMMDD(new Date()); if (currentDate == this.notify_timing) { return true; } else { return false; } } sendEmail(email: string, message: string): void { /* 通知処理 省略 */ } formatDateToYYYYMMDD(date: Date): string { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } getEmergencyContact(): string | undefined { return this.emergency_contact } setNextNotifyTiming(): void { if (this.category === '車検') { // 車検の場合は、expire_dateの1ヶ月前、3か月前、半年前に次の通知タ イミングをセット const today = new Date(); const one_month_before = this.calculateDateBefore(1); const three_months_before = this.calculateDateBefore(3); const six_months_before = this.calculateDateBefore(6); if (today < six_months_before) { console.log('今日は6か月前以前です'); this.notify_timing = this.formatDate(six_months_before); } else if (today >= six_months_before && today < three_months_before) { console.log('今日は3か月~6か月の間です'); this.notify_timing = this.formatDate(three_months_before); } else if (today >= three_months_before && today < one_month_before) { console.log('今日は3月~1か月前です'); this.notify_timing = this.formatDate(one_month_before); } } else if (this.category === '大型車定期点検' || this.category === '普通車定 期点検') { // 定期点検の場合は、まず次の点検タイミングをセット 大型車は3か月 、普通車は6か月 省略 } } //省略 } index.ts (エントリーポイント) 左のボックスの続き const car_inspection = new NotifierForInspectionAndInsurance( '車検', '[email protected]', '2024-11-03', '2024-08-04') if(car_inspection.isNotifyTiming()){ car_inspection.notify() }

Slide 20

Slide 20 text

20

Slide 21

Slide 21 text

21 名前がなんの ためのクラスか わかりにくい undefined許可の プロパティがある if文で分岐されてい るので、保険や点検 の種類が追加された らその都度if文を変 更しないといけない

Slide 22

Slide 22 text

22 保険 自賠責 保険 任意保険 点検 車検 定期点検 これで 理解はあって ますか? 重要ポイント: 構造図はわかりやすいの で顧客と会話できる! あってる

Slide 23

Slide 23 text

23 抽象スーパークラス 保険 (Insurance) クラス自賠責保険 (Mandatory Insurance) クラス任意保険 (Optional Insurance) 抽象スーパークラス 点検(Inspection) クラス車検 (CarInspection) クラス定期点検 (Periodic Inspection) 保険 自賠責 保険 任意 保険 点検 車検 定期 点検

Slide 24

Slide 24 text

24 抽象スーパークラス 保険 (Insurance) クラス自賠責保険 (Mandatory Insurance) クラス任意保険 (Optional Insurance) 抽象スーパークラス 点検 (Inspection) クラス車検 (CarInspection) クラス定期点検 (Periodic Inspection) <共通しそうな機能> ・通知を送る ・通知を送ったら次の通知タ イミングをセットする

Slide 25

Slide 25 text

25

Slide 26

Slide 26 text

26 抽象スーパークラス 保険・点検類 (InsuaranceAndInspection) 抽象スーパークラス 保険 (Insurance) クラス 自賠責保険 (MandatoryInsurance) クラス 任意保険 (OptionalInsurance) 抽象スーパークラス 点検 (Inspection) クラス 車検 (CarInspection) クラス 定期点検 (PeriodicInspection) 保険とメンテナンスは 有効期限がある、 任意のタイミングで通知する など共通する概念のものだと思 います。 だからスーパークラスを作って そこに実装するのがよいと思い ます。 スーパー クラス追加

Slide 27

Slide 27 text

27 左のボックスの続き index.ts (エントリーポイント) export abstract class InsuranceAndInspection { protected email : string protected expire_date: string protected notify_timing: string constructor(email: string, expire_date: string, notify_timing: string) { this.email = email this.expire_date = expire_date this.notify_timing = notify_timing } notify(): void { this.sendEmail(this.email, '通知処理') this.setNextNotifyTiming() } isNotifyTiming(): boolean { const currentDate = this.formatDate(new Date()); return currentDate == this.notify_timing } abstract setNextNotifyTiming(): void // sendEmail(),calculateDateBefore(),formatDate()は省略 } export abstract class Insurance extends InsuranceAndInspection { protected emergency_contact: string constructor(email: string, expire_date: string, notify_timing: string, emergency_contact: string) { super(email, expire_date, notify_timing) this.emergency_contact = emergency_contact } getEmergencyContact(): string { return this.emergency_contact } } export abstract class Insurance extends InsuranceAndInspection { protected emergency_contact: string constructor(email: string, expire_date: string, notify_timing: string, emergency_contact: string) { super(email, expire_date, notify_timing) this.emergency_contact = emergency_contact } getEmergencyContact(): string { return this.emergency_contact } } export abstract class Inspection extends InsuranceAndInspection { } export class CarInspection extends Inspection { setNextNotifyTiming(): void { // expire_dateの1ヶ月前、3か月前、半年前に次の通知タイミングをセット const today = new Date(); const one_month_before = this.calculateDateBefore(1); const three_months_before = this.calculateDateBefore(3); const six_months_before = this.calculateDateBefore(6); if (today < six_months_before) { console.log(‘今日は6か月前以前です’); this.notify_timing = this.formatDate(six_months_before); } // 以下、1ヶ月前、3か月前に次の通知タイミングをセットするコード 省略 } const car_inspection = new CarInspection( '[email protected]', '2024-11-03', '2024-08-04') if(car_inspection.isNotifyTiming()){ car_inspection.notify() }

Slide 28

Slide 28 text

28 保険と点検は別物じゃないです か?? 有効期限が切れる、 任意のタイミングで通知する は機能であって、構造ではない。 そこでインターフェースにするのが よいと思います。 有効期限を確認して通知するイン ターフェース定義して保険と 点検クラスに実装します。 抽象スーパークラス 保険 (Insurance) クラス自賠責保険 (Mandatory Insurance) クラス任意保険 (Optional Insurance) 抽象スーパークラス 点検(Inspection) クラス車検 (CarInspection) クラス定期点検 (Periodic Inspection) 有効期限を 確認して通知するインターフェース (NotifyByNeed) インターフェース追加

Slide 29

Slide 29 text

29 右上に続く export interface NotifyAndSetNextTiming { notify(): void isNotifyTiming(): boolean setNextNotifyTiming(): void } export abstract class Insurance implements NotifyAndSetNextTiming{ protected email : string protected expire_date: string protected notify_timing: string protected emergency_contact: string constructor(email: string, expire_date: string, notify_timing: string, emergency_contact: string) { this.email = email this.expire_date = expire_date this.notify_timing = notify_timing this.emergency_contact = emergency_contact } notify(): void { this.sendEmail(this.email, '通知処理') this.setNextNotifyTiming() } isNotifyTiming(): boolean { const currentDate = this.formatDate(new Date()); return currentDate == this.notify_timing } getEmergencyContact(): string { return this.emergency_contact } abstract setNextNotifyTiming(): void // sendEmail(),calculateDateBefore(),formatDate()は省略 } export abstract class Inspection implements NotifyAndSetNextTiming { protected email : string protected expire_date: string protected notify_timing: string constructor(email: string, expire_date: string, notify_timing: string) { this.email = email this.expire_date = expire_date this.notify_timing = notify_timing } notify(): void { this.sendEmail(this.email, ‘通知処理’) this.setNextNotifyTiming() } isNotifyTiming(): boolean { const currentDate = this.formatDate(new Date()); return currentDate == this.notify_timing } abstract setNextNotifyTiming(): void // sendEmail(),calculateDateBefore(),formatDate()は省略 } export class CarInspection extends Inspection { inspect(): boolean{ /* 点検処理 省略 */ return true } setNextNotifyTiming(): void { const today = new Date(); const one_month_before = this.calculateDateBefore(1); const three_months_before = this.calculateDateBefore(3); const six_months_before = this.calculateDateBefore(6); if (today < six_months_before) { console.log('今日は6か月前以前です'); this.notify_timing = this.formatDate(six_months_before); } } } エントリーポイント省略

Slide 30

Slide 30 text

30

Slide 31

Slide 31 text

31 左のボックスの続き index.ts (エントリーポイント) export abstract class InsuranceAndInspection { protected email : string protected expire_date: string protected notify_timing: string constructor(email: string, expire_date: string, notify_timing: string) { this.email = email this.expire_date = expire_date this.notify_timing = notify_timing } notify(): void { this.sendEmail(this.email, '通知処理') this.setNextNotifyTiming() } isNotifyTiming(): boolean { const currentDate = this.formatDate(new Date()); return currentDate == this.notify_timing } abstract setNextNotifyTiming(): void // sendEmail(),calculateDateBefore(),formatDate()は省略 } export abstract class Insurance extends InsuranceAndInspection { protected emergency_contact: string constructor(email: string, expire_date: string, notify_timing: string, emergency_contact: string) { super(email, expire_date, notify_timing) this.emergency_contact = emergency_contact } getEmergencyContact(): string { return this.emergency_contact } } export abstract class Insurance extends InsuranceAndInspection { protected emergency_contact: string constructor(email: string, expire_date: string, notify_timing: string, emergency_contact: string) { super(email, expire_date, notify_timing) this.emergency_contact = emergency_contact } getEmergencyContact(): string { return this.emergency_contact } } export abstract class Inspection extends InsuranceAndInspection { } export class CarInspection extends Inspection { setNextNotifyTiming(): void { // expire_dateの1ヶ月前、3か月前、半年前に次の通知タイミングをセット const today = new Date(); const one_month_before = this.calculateDateBefore(1); const three_months_before = this.calculateDateBefore(3); const six_months_before = this.calculateDateBefore(6); if (today < six_months_before) { console.log(‘今日は6か月前以前です’); this.notify_timing = this.formatDate(six_months_before); } // 以下、1ヶ月前、3か月前に次の通知タイミングをセットするコード 省略 } const car_inspection = new CarInspection( '[email protected]', '2024-11-03', '2024-08-04') if(car_inspection.isNotifyTiming()){ car_inspection.notify() } プロパティがnull 許可にならずに すんでいる if文の分岐になら ずに済んでいる

Slide 32

Slide 32 text

32 左のボックスの続き index.ts (エントリーポイント) export abstract class InsuranceAndInspection { protected email : string protected expire_date: string protected notify_timing: string constructor(email: string, expire_date: string, notify_timing: string) { this.email = email this.expire_date = expire_date this.notify_timing = notify_timing } notify(): void { this.sendEmail(this.email, '通知処理') this.setNextNotifyTiming() } isNotifyTiming(): boolean { const currentDate = this.formatDate(new Date()); return currentDate == this.notify_timing } abstract setNextNotifyTiming(): void // sendEmail(),calculateDateBefore(),formatDate()は省略 } export abstract class Insurance extends InsuranceAndInspection { protected emergency_contact: string constructor(email: string, expire_date: string, notify_timing: string, emergency_contact: string) { super(email, expire_date, notify_timing) this.emergency_contact = emergency_contact } getEmergencyContact(): string { return this.emergency_contact } } export abstract class Insurance extends InsuranceAndInspection { protected emergency_contact: string constructor(email: string, expire_date: string, notify_timing: string, emergency_contact: string) { super(email, expire_date, notify_timing) this.emergency_contact = emergency_contact } getEmergencyContact(): string { return this.emergency_contact } } export abstract class Inspection extends InsuranceAndInspection { } export class CarInspection extends Inspection { setNextNotifyTiming(): void { // 車検の場合は、expire_dateの1ヶ月前、3か月前、半年前に次の通知タイミングを セット const today = new Date(); const one_month_before = this.calculateDateBefore(1); const three_months_before = this.calculateDateBefore(3); const six_months_before = this.calculateDateBefore(6); if (today < six_months_before) { console.log(‘今日は6か月前以前です’); this.notify_timing = this.formatDate(six_months_before); } // 以下、1ヶ月前、3か月前に次の通知タイミングをセットするコード 省略 } const car_inspection = new CarInspection( '[email protected]', '2024-11-03', '2024-08-04') if(car_inspection.isNotifyTiming()){ car_inspection.notify() } 名前が長いし違 うものを一緒にし ている感じがする

Slide 33

Slide 33 text

33 右上に続く export interface NotifyAndSetNextTiming { notify(): void isNotifyTiming(): boolean setNextNotifyTiming(): void } export abstract class Insurance implements NotifyAndSetNextTiming{ protected email : string protected expire_date: string protected notify_timing: string protected emergency_contact: string constructor(email: string, expire_date: string, notify_timing: string, emergency_contact: string) { this.email = email this.expire_date = expire_date this.notify_timing = notify_timing this.emergency_contact = emergency_contact } notify(): void { this.sendEmail(this.email, '通知処理') this.setNextNotifyTiming() } isNotifyTiming(): boolean { const currentDate = this.formatDate(new Date()); return currentDate == this.notify_timing } getEmergencyContact(): string { return this.emergency_contact } abstract setNextNotifyTiming(): void // sendEmail(),calculateDateBefore(),formatDate()は省略 } export abstract class Inspection implements NotifyAndSetNextTiming { protected email : string protected expire_date: string protected notify_timing: string constructor(email: string, expire_date: string, notify_timing: string) { this.email = email this.expire_date = expire_date this.notify_timing = notify_timing } notify(): void { this.sendEmail(this.email, ‘通知処理’) this.setNextNotifyTiming() } isNotifyTiming(): boolean { const currentDate = this.formatDate(new Date()); return currentDate == this.notify_timing } abstract setNextNotifyTiming(): void // sendEmail(),calculateDateBefore(),formatDate()は省略 } export class CarInspection extends Inspection { inspect(): boolean{ /* 点検処理 省略 */ return true } setNextNotifyTiming(): void { const today = new Date(); const one_month_before = this.calculateDateBefore(1); const three_months_before = this.calculateDateBefore(3); const six_months_before = this.calculateDateBefore(6); if (today < six_months_before) { console.log('今日は6か月前以前です'); this.notify_timing = this.formatDate(six_months_before); } } } エントリーポイント省略 重複するプロパ ティ、内容が同じ メソッドが多く存 在している

Slide 34

Slide 34 text

34 • 概念が似ているもの • チンパンジーと猿、請求書と納品書、などのように同じようなも のとみなせる • 使うシーンが似ている • 見た目が似ているもの • 画面に置くボタンや表などの構造体 • 同じ種類と言えるもの • isAの関係にある なぜか?

Slide 35

Slide 35 text

35 • 理解しやすい • 部屋の中のモノが雑多に散らかってい るよりも、箱に入れて整理したほうがわ かりやすいように、何か箱に入れてまと めるとプログラム全体の見通しがよくな る • 将来的に同じような機能を実装する 可能性が高い • 請求書と納品書は担当者にメールする 機能が次に実装される、など

Slide 36

Slide 36 text

36 • シンプルな機能 • 通知、クリックできる、走ることができる、など • 汎用的 • 色々なプログラムで使いそう • ○○ しないといけない、○○できる、○○を 持っている などと言い表せる なぜか?

Slide 37

Slide 37 text

37 • インターフェースは実装を書けないので(大体 の言語において)小さい機能の実装が適して いる • 取り外ししやすい • その機能がいらなくなる時に外すのが簡単 • 逆につけたい場合に、つけるのが簡単 • クラスに複数のインターフェースを実装することが可能 なので、複雑な機能をインターフェースに実装すると、 混乱しやすい

Slide 38

Slide 38 text

38

Slide 39

Slide 39 text

39 例えば、保険と点検を現実の生活で考えてみ ると実際に形を成すのは 「保険証書」 「点検の記録」。 そこに何が書かれそうか? どの車の保険なのか、どの車の点検なのかは 重要な情報になりそう。 車に紐づく情報として、車の情報を両方とも 持っている。有効期限も大事。 また、事故の場合にとりださなければいけない 情報、という意味でも似ている。 つまり、保険と点検は性質が似ているといえる。

Slide 40

Slide 40 text

40 抽象スーパークラス 保険・点検類 (InsuaranceAndInspection) 抽象スーパークラス 保険 (Insurance) クラス 自賠責保険 (MandatoryInsurance) クラス 任意保険 (OptionalInsurance) 抽象スーパークラス 点検 (Inspection) クラス 車検 (CarInspection) クラス 定期点検 (PeriodicInspection) 有効期限を 確認して通知するインターフェース (NotifyByNeed) インターフェース追加 スーパー クラス追加

Slide 41

Slide 41 text

41 伝わりはするが クラスの名前が よくない 一番この分野に 詳しい人に相談する この場合は顧客 抽象スーパークラス 保険・点検類 (InsuaranceAndInspection) 抽象スーパークラス 保険 (Insurance) クラス 自賠責保険 (MandatoryInsurance) クラス 任意保険 (OptionalInsurance) 抽象スーパークラス 点検 (Inspection) クラス 車検 (CarInspection) クラス 定期点検 (PeriodicInspection) 有効期限を 確認して通知するインターフェース (NotifyByNeed)

Slide 42

Slide 42 text

42 そんな、お客さんにはプログラミングの ことなんか一切わからないのに、 「スーパークラスの名前をどうするか」 なんて相談したってわかりっこないです よ!! それに、大事なことをわかっていないよ うに思われて、システム屋としてのこち らの信用を下げてしまいます!

Slide 43

Slide 43 text

43

Slide 44

Slide 44 text

44 重要ポイント: 構造図はわかりやすいの で顧客と会話できる! 以前お見せした構造 図をちょっと変えて、保 険と点検をまとめよう と思っています。 保険と点検をまとめた 用語がありますか? それなら「メンテナン ス」だね。 弊社では、今Excelで 管理しているんだけど、 「メンテナンス台帳」 というファイル名なん だ。 保険・点検類 保険 自賠責保険 任意保険 点検 車検 定期点検

Slide 45

Slide 45 text

45 スライド19時点 2回も

Slide 46

Slide 46 text

46 抽象スーパークラス メンテナンス (Maintenance) 抽象スーパークラス 保険 (Insurance) クラス 自賠責保険 (MandatoryInsurance) クラス 任意保険 (OptionalInsurance) 抽象スーパークラス 点検 (Inspection) クラス 車検 (CarInspection) クラス 定期点検 (PeriodicInspection) 有効期限を 確認して通知するインターフェース (NotifyByNeed) メンテナンスという名前に変更

Slide 47

Slide 47 text

47 なるほど、保険と点検は別物じゃないか と思っていましたが、「メンテナンス」と言 われれば、確かに同じ概念だと腑に落 ちます! そこで思いついたのが、「メンテナンス」 というのは「ほったらかしにしておくわけ にはいかない」というモノだと思います。 つまり、有効期限があったり通知する必 要があるということだと思います。 そこで、通知タイミングに関する機能は メンテナンスクラスに実装しておけばわ かりやすいんじゃないでしょうか? メンテナンス (Maintenance) 保険 (Insurance) 自賠責保険 (MandatoryInsurance) 任意保険 (OptionalInsurance) 点検 (Inspection) 車検 (CarInspection) 定期点検 (PeriodicInspection)

Slide 48

Slide 48 text

48 すっきりして わかりやすい! 削除 抽象スーパークラス メンテナンス (Maintenance) 抽象スーパークラス 保険 (Insurance) クラス 自賠責保険 (MandatoryInsurance) クラス 任意保険 (OptionalInsurance) 抽象スーパークラス 点検 (Inspection) クラス 車検 (CarInspection) クラス 定期点検 (PeriodicInspection) 有効期限を確認して 通知するインターフェース (NotifyByNeed) 通知のタイミングを計るメ ソッドはMaintenanceクラス へ移動

Slide 49

Slide 49 text

49 左のボックスの続き index.ts (エントリーポイント) export abstract class Insurance extends Maintenance { protected emergency_contact: string constructor(email: string, expire_date: string, notify_timing: string, emergency_contact: string) { super(email, expire_date, notify_timing) this.emergency_contact = emergency_contact } getEmergencyContact(): string { return this.emergency_contact } } export class CarInspection extends Inspection { inspect(): boolean{ /* 点検処理 省略 */ return true } setNextNotifyTiming(): void { // 車検の場合は、expire_dateの1ヶ月前、3か月前、半年前に次の通知タイミングをセット const today = new Date(); const one_month_before = this.calculateDateBefore(1); const three_months_before = this.calculateDateBefore(3); const six_months_before = this.calculateDateBefore(6); if (today < six_months_before) { console.log('今日は6か月前以前です'); this.notify_timing = this.formatDate(six_months_before); }// 以下、1ヶ月前、3か月前に次の通知タイミングをセットするコード 省略 } } const car_inspection = new CarInspection( '[email protected]', '2024-11-03', '2024-08-04') if(car_inspection.isNotifyTiming()){ car_inspection.notify() } export interface Notify { notify(): void } export abstract class Maintenance implements Notify{ protected email : string protected expire_date: string protected notify_timing: string constructor(email: string, expire_date: string, notify_timing: string) { this.email = email this.expire_date = expire_date this.notify_timing = notify_timing } notify(): void { this.sendEmail(this.email, '通知処理') this.setNextNotifyTiming() } isNotifyTiming(): boolean { const currentDate = this.formatDate(new Date()); return currentDate == this.notify_timing } abstract setNextNotifyTiming(): void // sendEmail(),calculateDateBefore(),formatDate()は省略 } export abstract class Inspection extends Maintenance { abstract inspect(): boolean } index.ts (エントリーポイント)

Slide 50

Slide 50 text

50

Slide 51

Slide 51 text

51 ・ドメインエキスパート(ここでは顧客)との会話や ドメインエキスパートの使う言葉に注目する

Slide 52

Slide 52 text

52 ・言語により概念が広がり、設計がよりわかりやすくなる 発想が出てくる

Slide 53

Slide 53 text

53 概念の整理なんて、誰にもできる じゃないですか! 一般の人ができない難しいことを やることこそが かっこいいプログラマーじゃない ですか! かっこいいことを やりたいんですけど!

Slide 54

Slide 54 text

54