Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
オブジェクト指向 パラメータ多相・実装継承 / OOP3
Search
nrs
October 28, 2018
Programming
3
3.4k
オブジェクト指向 パラメータ多相・実装継承 / OOP3
勉強会での登壇用資料です。
オブジェクト指向のパラメータ多相と実装継承 についての解説です。
https://nrslib.com
nrs
October 28, 2018
Tweet
Share
More Decks by nrs
See All by nrs
イベントストーミングによるオブジェクトモデリング・オブジェクト指向プログラミングの適用・開発プロセスの変遷・アーキテクチャの変革 / Object modeling with Event Storming.
nrslib
13
5.3k
Deep Dive 大規模システムアーキテクチャ/開発組織エンジニアリング / Deep Dive Large-Scale System Architecture, Development Organization Engineering
nrslib
15
3.2k
アーキテクチャ刷新の現場 / Scene of architectural renewal
nrslib
7
1.9k
実践PubSubマイクロサービス / Implementation Pub Sub microservice
nrslib
5
1.4k
スケーラブルシステム / Scalable System
nrslib
3
1.1k
隠されたトークンあるいは暗号の解説 / Explanation of hidden tokens or cryptography
nrslib
0
260
越境のデザイン / border crossing design
nrslib
3
540
依存関係のコントロール / Dependency Control
nrslib
3
3.2k
マイクロサービスでイベントソーシングを利用したくなる理由とその動作原理を学ぼう / Why Event Sourcing
nrslib
4
1.8k
Other Decks in Programming
See All in Programming
How to improve maintainability and readability of your automated tests? ( #scrumniigata )
teyamagu
PRO
1
130
AppRouter Panel Talk
yosuke_furukawa
PRO
1
530
欠陥を早期に発見するための Software Engineer in Test とその重要性 / What is Software Engineer in Test and How they works
orgachem
PRO
19
2.5k
Unlocking Potential of Property Based Testing with Ractor
ohbarye
2
470
Try creating your own orderedmap
kazamori
1
290
Namespace, What and Why
tagomoris
4
1.1k
“Seeing Like a Programmer”—Resiliency, Limits, and Moral Hazards in Software Engineering (LambdaConf 2024)
chriskrycho
0
440
TypeScriptでもLLMアプリケーション開発 / LLM Application In Typescript
rkaga
5
1.3k
TypeScriptの型とパフォーマンス (TSKaigi 2024)
ypresto
14
5.2k
RailsConf 2024: Riffing on Rails: sketch your way to better designed code
kaspth
1
220
2024 コーディング研修
ckazu
2
670
FoodGram
iseruuuuu
0
230
Featured
See All Featured
Bash Introduction
62gerente
605
210k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
22
1.6k
Product Roadmaps are Hard
iamctodd
45
9.8k
Typedesign – Prime Four
hannesfritz
36
2.1k
The Straight Up "How To Draw Better" Workshop
denniskardys
228
130k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
15
1.6k
Pencils Down: Stop Designing & Start Developing
hursman
117
11k
A Philosophy of Restraint
colly
197
16k
Thoughts on Productivity
jonyablonski
60
3.9k
Keith and Marios Guide to Fast Websites
keithpitt
408
22k
Intergalactic Javascript Robots from Outer Space
tanoku
266
26k
Bootstrapping a Software Product
garrettdimon
PRO
302
110k
Transcript
オブジェクト指向入門 パラメータ多相 実装継承 nrs @nrslib
パラメータ多相
パラメータ = ?
ArrayList
ArrayList キャストすれば計算はできる
ArrayList 実行時エラー もし文字列を代入したら?
ArrayList 実行時エラー
ArrayList
ArrayList 型を意識する必要が出てしまう
問題点 ? =
問題点 キャスト =
キャストをするということは 問題点 キャスト =
キャストをするということは list 変数には 数字しか入らないという 暗黙的なルールがある 問題点 キャスト =
キャストをするということは 暗黙的なルール = ランタイムエラーの原因 list 変数には 数字しか入らないという 暗黙的なルールがある 問題点 キャスト
=
どうすれば解決できるのか
どうすれば解決できるのか ランタイムエラーではなく コンパイルエラーにする
どうすれば解決できるのか ランタイムエラーではなく コンパイルエラーにする ジェネリクス(総称型)
List<T> int 型の List と宣言
List<T> int 型の List と宣言 int 型は要素として追加できる
List<T> int 型の List と宣言 int 型は要素として追加できる int 型の List
の要素なので int 型 (キャスト不要!)
List<T> int 型以外の要素追加は コンパイルエラー
パラメータ = ?
パラメータ = ?
パラメータ = 型
パラメータ = 型 パラメータ多相は型情報を抽象化する 型を抽象化して捉えることで 特定の型に捉われない実装を行える
エクササイズ
お題はエラーコード
エラーコード
エラーコード エラーコードってどう扱っていますか 形式は数字ですか? 文字列ですか? 粒度はどれくらいですか?
エラーコード 形式は列挙体で 粒度はユースケース毎 にしようと思いました
エラーコード
エラーコード
エラーコード ユースケース毎に起こりうるエラーがわかる
エラーコード ユースケース毎に起こりうるエラーがわかる -> エラーコードからの該当箇所特定が容易
レスポンス どんなクラスを作る?
レスポンス
レスポンス
レスポンス
レスポンス
レスポンス 似たようなコードが多いので スーパークラスを作ります
スーパークラス
スーパークラス
スーパークラス
スーパークラス
使ってみよう
使ってみよう
使ってみよう
使ってみよう もしエラーコードで メッセージを出し分けしたかったら?
エラーコードでメッセージを出し分け
エラーコードでメッセージを出し分け イマイチポイント① キャスト
エラーコードでメッセージを出し分け キャスト 実際のクラスを知っている = イマイチポイント① キャスト
エラーコードでメッセージを出し分け イマイチポイント② 他のレスポンスでも 似たようなロジックを 書くことになりそう
目標はこんな感じ
実装してみよう 目標はこんな感じ
まずはキャスト撲滅
object を使っているところを
ジェネリクスに
ジェネリクスに
レスポンスが変更されます
レスポンスが変更されます
キャスト消失
キャスト消失
次はここ
一旦の目標
エラーメッセージに変換するモジュール
エラーメッセージに変換するモジュール Q. 他のエラーコードにも対応させたら?
None
イマイチポイント 型確認
イマイチポイント キャスト イマイチポイント 型確認
イマイチポイント キャスト イマイチポイント 型確認 イマイチポイント どんどん増える
イマイチポイント キャスト イマイチポイント 型確認 イマイチポイント どんどん増える 総評 イマイチ
そもそもエラーコードに対応する メッセージはどこに書くべきか
エラーコードに書きたい
エラーコードに書きたい ※多言語化するときはメッセージIDです
エラーコードからエラーメッセージを設定する
エラーコードからエラーメッセージを設定する
エラーコードからエラーメッセージを取得する
エラーコードからエラーメッセージを取得する {UserPostErrorCode.IllegalCharactorOnUserName, ErrorMessageAttribute(“ユーザ名に利用できない文字が存在しています”)}, {UserPostErrorCode.DuplicatedUserName, ErrorMessageAttribute(“ユーザー名が重複しています”)} という連想配列を作ってる
モジュール化してみる
モジュール化してみる
モジュール化してみる これを使うとこうなる
モジュール化してみる オートボクシング発生
オートボクシングを防ぐには
オートボクシングを防ぐには object を使わなければいい
オートボクシングを防ぐには object を使わなければいい ジェネリクス
None
めでたしめでたし…
と思いきや
使ってみると
使ってみると 型を書かなくてはいけない
使ってみると 型を書かなくてはいけない 型は大事だけど 型を意識する役目はコンパイラ
型を書かなくてもいいように 改良しよう
まずは少しでもタイプセーフにするために マークアップインターフェースを用意 (object で扱えばいいので必須ではないです)
メッセージ取得部分をクラスに
作ったクラスを利用する
出来上がった最終形
型を意識しないようにすると
最終形は?
拡張メソッドで
拡張メソッドで 拡張メソッドは乱用不可 継承でも実現できる 拡張メソッドを採用する理由は要検討
拡張メソッドで 拡張メソッドは乱用不可 継承でも実現できる 拡張メソッドを採用する理由は要検討 今回の採用理由は メッセージ処理はプレゼンテーション層の処理 Response というオブジェクトが担保すべきでない
ジェネリクスの制約について
制約 型パラメータに条件を付ける機能
制約
制約 Response のメソッド 呼びたいけど
制約 Response のメソッド 呼びたいけど 型がわからない
制約 TResponse は Response か Response のサブタイプである と定義
制約 TResponse は Response か Response のサブタイプである と定義 ToErrorMessage() が呼べる
共変 / 反変
共変 / 反変 頭がこんがらがるので省略
共変 / 反変 頭がこんがらがるので省略 in 修飾子 out 修飾子 こういうことを可能にします
ジェネリクスまとめ 本来やりたいことは object で実現できる でも型の恩恵は受けたいので型を抽象化した
実装継承の話をします
継承は
継承は ポリモーフィズムを 実現するための機能である
継承は ポリモーフィズムを 実現するための機能である
継承は コードの共通化を 実現するための機能である
なぜこれを強調するのか
継承はとても難しいから なぜこれを強調するのか
継承の難しさ
継承の難しさ
継承の難しさ
継承の難しさ
継承の難しさ 継承構造は利用者次第 作成者が関与できない
None
None
None
メソッドを override するかしないか
メソッドを override するかしないか これは形を変えた条件分岐
合わさるとやばい
サブタイプのための継承が行われる
サブタイプのための継承が行われる
サブタイプのための継承が行われる
サブタイプのための継承が行われる スーパークラスで 利用されていない
サブタイプのための継承が行われる スーパークラスで 利用されていない 共通化すべき処理が 発見されたとき もう継承できない
こんな感じがおすすめ
こんな感じがおすすめ
こんな感じがおすすめ 共通化する目的は 改修する時に変更箇所を集約することが目的 書く時に楽をするためだけの継承はしてはいけない
もはやそれは別物だよ
もはやそれは別物だよ
もはやそれは別物だよ is-a 関係の難しさ
まとめ 結果として出来上がる継承構造の形成に関して スーパークラスの製作者が制御する仕組みがない オーバーライドできるメソッドの数により複雑さが増す サブタイプのための継承が可能だが 本来の目的から反する クラスハックのための継承が行われることがあり 驚き最小の原則に反する
継承の怖さについて学んだところで 継承をしてみよう
None
まずは 重複していないところを チェック
None
None
None
継承方針を決める
継承方針を決める スーパークラスは何か
継承方針を決める スーパークラスは何か 「ファイルを出力するコマンド」
None
この部分は virtual メソッドで用意する?
もし用意したらどうなる?
たぶんこうなる
この部分は virtual メソッドで用意する?
この部分は virtual メソッドで用意する? → No! 振る舞いがないのでパラメータで十分
None
この部分は virtual メソッドで用意する?
この部分は virtual メソッドで用意する? → Yes ! 振る舞いがあるので override 必要
スーパークラス
スーパークラス パラメータで受け取り
スーパークラス 振る舞いは変更可能
継承すると
継承すると
継承すると
継承すると 差分に集中できる
よりよいスーパークラス
よりよいスーパークラス 現在のインターフェース
よりよいスーパークラス 必ず実装してほしい 現在のインターフェース
よりよいスーパークラス
よりよいスーパークラス
よりよいスーパークラス 仮実装不要
よりよいスーパークラス インターフェース
よりよいスーパークラス インターフェース
よりよいスーパークラス インターフェース 継承前提のクラスだと わかる
よりよいスーパークラス インターフェース 実装しないと コンパイルエラー 継承前提のクラスだと わかる
実は継承を使わずに 同様のことを実現ができます
None
関数を引数で受け取る
利用イメージ
利用イメージ
継承するかしないか
継承するかしないか 継承 Ver. 関数 Ver.
継承するかしないか 継承 Ver. 関数 Ver. 重複!
継承するかしないか 継承したクラス自体を 再利用するとき継承する 継承 Ver. 関数 Ver.
関数を受け取るクラスの継承
関数を受け取るクラスの継承
override されるメソッドについて 簡単なガイドライン
範囲を小さく 初期化処理に サブクラスで追加処理したい
範囲を小さく
範囲を小さく
範囲を小さく super.Initialize()を 呼ばないと スーパークラスの初期化が発生しない
範囲を小さく super.Initialize()を 呼ばないと スーパークラスの初期化が発生しない =スーパークラスの破壊が可能
範囲を小さく
スーパークラスの 初期化を担保している 範囲を小さく
ネーミング
ネーミング 初期化処理の前 初期化処理の後
ネーミング 初期化処理の前 初期化処理の後 Hook するメソッドが処理の最初か最後かは 重要な要素であったりするので 現在進行形と過去形で使い分ける
実装継承まとめ 処理の共通化が目的 共通化することで改修する時の変更箇所を集約する 振る舞いがあるかどうかは継承をするかの大事な判断基準
Auther nrs HomePage https://nrslib.com Twitter @nrslib