WEBVTT

1
00:00:00.000 --> 00:00:01.023
こんにちは。

2
00:00:01.023 --> 00:00:06.136
今回のテーマは、タイプスクリプトのオブジェクト指向設計です。

3
00:00:06.136 --> 00:00:17.385
オブジェクト指向では、関連するデータと、そのデータを扱う処理をまとめ、役割のあるオブジェクト同士を組み合わせてプログラムを作ります。

4
00:00:17.385 --> 00:00:19.260
柱になるのは三つです。

5
00:00:19.260 --> 00:00:29.146
状態の変え方を限定するカプセル化、共通の約束を決めるインターフェース、そして仕事を別のオブジェクトへ任せる委譲です。

6
00:00:29.146 --> 00:00:34.088
クラスを増やせば自動的に保守性が上がるわけではありません。

7
00:00:34.088 --> 00:00:39.798
変更の影響範囲が分かること、状態の更新方法が明確なこと、必要な処理を差し替えやすいことを目標に、

8
00:00:39.798 --> 00:00:45.508
記事の二つの例で確認していきましょう。

9
00:00:45.508 --> 00:00:46.722
まず基本です。

10
00:00:46.722 --> 00:00:51.060
オブジェクトは、プロパティやメソッドを持つ値です。

11
00:00:51.060 --> 00:00:56.785
クラスは、そのようなオブジェクトを作成する方法の一つにすぎません。

12
00:00:56.785 --> 00:01:04.765
オブジェクトリテラルでも作れるため、すべてのオブジェクトにクラスが必要なわけではありません。

13
00:01:04.765 --> 00:01:08.756
では、どんなときにクラスが役立つのでしょうか。

14
00:01:08.756 --> 00:01:13.440
例えば記事の公開状態を管理するなら、状態と、状態を変更する処理を一緒に置くと、

15
00:01:13.440 --> 00:01:18.124
変更箇所を追いやすくなります。

16
00:01:18.124 --> 00:01:24.196
逆に、状態を持たない短い変換処理なら、関数だけで十分な場合もあります。

17
00:01:24.196 --> 00:01:31.136
道具ありきではなく、まとめたい状態と操作があるかどうかで判断するのが出発点です。

18
00:01:31.136 --> 00:01:35.065
カプセル化の実例が、アーティクルステータスクラスです。

19
00:01:35.065 --> 00:01:41.905
公開したかどうかを表すフラグは、シャープ付きのフィールドにして外から直接触れないようにします。

20
00:01:41.905 --> 00:01:46.198
タイトルはコンストラクタ引数のリードオンリーで受け取り、空のタイトルならエラーを投げて、

21
00:01:46.198 --> 00:01:50.491
そもそも作れないようにします。

22
00:01:50.491 --> 00:01:53.983
状態を変える入口はパブリッシュメソッドだけです。

23
00:01:53.983 --> 00:01:57.767
表示用のラベルはゲットラベルメソッドが組み立てます。

24
00:01:57.767 --> 00:02:03.079
実行すると、最初はタイプスクリプトの設計コロン下書き、パブリッシュした後は、

25
00:02:03.079 --> 00:02:08.390
タイプスクリプトの設計コロン公開中と表示され、記事の期待どおりでした。

26
00:02:08.390 --> 00:02:12.756
状態の操作方法を限定すること、これがカプセル化の具体例です。

27
00:02:12.756 --> 00:02:15.530
ここで仕組みの違いを整理します。

28
00:02:15.530 --> 00:02:25.413
シャープ付きフィールドはジャバスクリプトのプライベートフィールドで、実行時にもクラス外から直接アクセスできません。

29
00:02:25.413 --> 00:02:32.175
外から読もうとすると、コンパイルの段階でエラーになることも実機で確認しました。

30
00:02:32.175 --> 00:02:37.117
一方、タイプスクリプトのプライベートやリードオンリーは、型チェック上の制約で、

31
00:02:37.117 --> 00:02:42.058
シャープ付きとは仕組みが異なります。

32
00:02:42.058 --> 00:02:47.433
タイトルが空でないかの確認は、型とは別に実行時に行う検証です。

33
00:02:47.433 --> 00:02:52.981
空白だけのタイトルで作ろうとすると例外になることも確認済みです。

34
00:02:52.981 --> 00:02:56.969
なお、この例が扱うのはメモリ上の状態だけです。

35
00:02:56.969 --> 00:03:02.344
データベースへの保存や、本番サイトへの公開処理は含まれません。

36
00:03:02.344 --> 00:03:04.263
次にインターフェースです。

37
00:03:04.263 --> 00:03:11.642
メッセージライターというインターフェースは、文字列を受け取るライトメソッド一つを契約として決めます。

38
00:03:11.642 --> 00:03:14.299
これを実装するのが二つのクラスです。

39
00:03:14.299 --> 00:03:21.826
コンソールライターは受け取った文字列をそのまま画面へ出し、メモリライターは内部の配列へためておきます。

40
00:03:21.826 --> 00:03:27.582
クラスにインプリメンツと書くと、その契約を満たしているかが型チェックされます。

41
00:03:27.582 --> 00:03:32.895
ライトメソッドを書き忘れたクラスはエラーになることも実機で確認しました。

42
00:03:32.895 --> 00:03:38.060
同じ契約で異なる実装を扱えることが、次の委譲と多態性の土台になります。

43
00:03:38.060 --> 00:03:43.964
インターフェース自体は実行時には残らない、型の契約である点も覚えておきましょう。

44
00:03:43.964 --> 00:03:51.109
アーティクルサービスは、通知の文面を作る役割に集中し、実際の出力は別のオブジェクトへ任せます。

45
00:03:51.109 --> 00:03:52.325
これが委譲です。

46
00:03:52.325 --> 00:03:56.125
コンストラクタでメッセージライター型の値を受け取り、アナウンスメソッドは、

47
00:03:56.125 --> 00:03:59.925
そのライトを呼ぶだけです。

48
00:03:59.925 --> 00:04:04.638
具体的な出力先を内部で固定していないため、コンソールライターを渡せば画面へ、

49
00:04:04.638 --> 00:04:09.350
メモリライターを渡せば記録へと切り替えられます。

50
00:04:09.350 --> 00:04:13.531
実行結果は、新着記事コロン型の使い方、と、配列に新着記事コロンクラスの使い方が入った形で、

51
00:04:13.531 --> 00:04:17.711
記事と一致しました。

52
00:04:17.711 --> 00:04:23.336
同じ契約で実装を差し替えて扱うことを、ポリモーフィズム、多態性と呼びます。

53
00:04:23.336 --> 00:04:26.832
継承を使わなくても実現できる点がポイントです。

54
00:04:26.832 --> 00:04:30.562
メモリライターの細部にもカプセル化の工夫があります。

55
00:04:30.562 --> 00:04:36.730
ゲットメッセージズは、内部の配列そのものではなく、中身を複製した新しい配列を返します。

56
00:04:36.730 --> 00:04:40.890
もし内部配列をそのまま渡すと、呼び出し側が要素を追加したり書き換えたりしただけで、

57
00:04:40.890 --> 00:04:45.049
内部の記録まで変わってしまいます。

58
00:04:45.049 --> 00:04:47.775
コピーを返せば、その心配がありません。

59
00:04:47.775 --> 00:04:54.947
さらに戻り値の型にリードオンリーを付けると、タイプスクリプトの型チェックでも変更操作が制限されます。

60
00:04:54.947 --> 00:04:57.673
隠すのはフィールドだけではありません。

61
00:04:57.673 --> 00:05:02.980
取り出すときの渡し方まで含めて、状態の守り方を設計するのがカプセル化です。

62
00:05:02.980 --> 00:05:08.061
継承と委譲は、どちらが優れているかではなく、目的で使い分けます。

63
00:05:08.061 --> 00:05:15.048
継承は、既存のクラスをエクステンズで拡張し、親クラスとして扱える子クラスを作る方法です。

64
00:05:15.048 --> 00:05:20.446
共通の実装をまとめられる一方、親クラスの変更が子クラスへ影響します。

65
00:05:20.446 --> 00:05:26.321
同じ種類のオブジェクトとして扱えて、共通の実装も必要なら継承を検討します。

66
00:05:26.321 --> 00:05:32.831
一方、ある機能だけを交換・再利用したいなら、インターフェースと委譲が向いています。

67
00:05:32.831 --> 00:05:35.689
今回の出力先の差し替えがその例です。

68
00:05:35.689 --> 00:05:42.358
そして、状態を持たない短い変換処理なら、クラスにせず関数だけで十分な場合もあります。

69
00:05:42.358 --> 00:05:48.392
再利用したいのが実装なのか、機能なのかを先に言葉にすると、判断がぶれません。

70
00:05:48.392 --> 00:05:49.384
実行方法です。

71
00:05:49.384 --> 00:05:54.488
記事の例は、ストリクト、ターゲット・イーエス2020、モジュール・ノードネクストを指定してコンパイルし、

72
00:05:54.488 --> 00:05:59.592
生成されたジャバスクリプトを実行します。

73
00:05:59.592 --> 00:06:05.688
ファイルは二つ、アーティクルステータスとメッセージサービスで、それぞれ分けて試します。

74
00:06:05.688 --> 00:06:11.926
今回の検証でも、両ファイルともこの設定でコンパイルでき、出力がすべて記事と一致しました。

75
00:06:11.926 --> 00:06:16.605
二つ目の例は、外部サービスへの送信やネットワーク接続を行いません。

76
00:06:16.605 --> 00:06:22.134
依存する処理を差し替える考え方を、自分のパソコンの中だけで安全に確認できます。

77
00:06:22.134 --> 00:06:29.364
エラー時はジャバスクリプトが出力されない設定なので、古い出力の実行と混同しない点にも注意してください。

78
00:06:29.364 --> 00:06:32.297
最後に、オブジェクトの責務の見直しです。

79
00:06:32.297 --> 00:06:38.311
一つのクラスが、入力の検証、通信、表示をすべて担当すると、変更の影響が広がります。

80
00:06:38.311 --> 00:06:44.765
何の理由で修正される処理なのかを考え、独立して差し替えたい部分を別の役割に分けましょう。

81
00:06:44.765 --> 00:06:47.698
もう一つの観点が、テストのしやすさです。

82
00:06:47.698 --> 00:06:52.098
外部サービスの呼び出しのような依存を、引数やコンストラクタから渡せる形にしておくと、

83
00:06:52.098 --> 00:06:56.498
テストでは小さな代替実装を使えます。

84
00:06:56.498 --> 00:07:03.979
今回のメモリライターがまさにその役割で、実際の通信をしなくても、呼び出し側の振る舞いを確かめられます。

85
00:07:03.979 --> 00:07:07.792
設計の良し悪しは、テストのしやすさにも表れるのです。

86
00:07:07.792 --> 00:07:08.689
まとめです。

87
00:07:08.689 --> 00:07:13.322
カプセル化では、状態を隠し、変更の入口をメソッドへ限定します。

88
00:07:13.322 --> 00:07:18.853
インターフェースで契約を決めれば、実装を差し替えて扱う多態性が得られます。

89
00:07:18.853 --> 00:07:25.728
そして委譲では、必要な機能を別のオブジェクトへ任せ、自分のクラスは本来の役割に集中させます。

90
00:07:25.728 --> 00:07:31.408
継承は共通の実装が必要なときに選び、短い処理は関数で済ませる判断も大切です。

91
00:07:31.408 --> 00:07:36.042
練習として、メッセージライターの三つ目の実装、例えば件数だけ数えるライターを作り、

92
00:07:36.042 --> 00:07:40.675
アーティクルサービスへ渡してみてください。

93
00:07:40.675 --> 00:07:45.907
呼び出し側を一行も変えずに差し替えられれば、設計の狙いが体感できます。

94
00:07:45.907 --> 00:07:47.252
お疲れさまでした。
