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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
nrs
October 28, 2018
Programming
4.2k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
オブジェクト指向 パラメータ多相・実装継承 / OOP3
勉強会での登壇用資料です。
オブジェクト指向のパラメータ多相と実装継承 についての解説です。
https://nrslib.com
nrs
October 28, 2018
More Decks by nrs
See All by nrs
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
1
280
どこまでを引き受けるのか — 変わり続ける役割と、変わらない思考法 / How Much We Take On — Evolving Roles and Enduring Ways of Thinking
nrslib
2
1.2k
決定論的オーケストレーションの設計と実装 / Design and Implementation of Deterministic Orchestration
nrslib
4
1.7k
実装は速くなった、レビューはどうする? ― 自身のレビューをAIで再現させるサーヴァントエンジニアリングのすゝめ / Implementation got faster. So what about reviews? — An invitation to Servant Engineering: Recreating your own code reviews with AI
nrslib
9
5.6k
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
15
6.5k
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
340
脅威をエンジニアリングの糧にして:恐怖を乗り越えた先にあったもの / Turn threats into fuel for engineering: what lay beyond overcoming fear
nrslib
1
470
AIチームを指揮するOSS「TAKT」活用術 / How to Use “TAKT,” an OSS Tool for Orchestrating AI Teams
nrslib
6
1.1k
実践ハーネスエンジニアリング:ステアリングループを実例から読み解く / Practical Harness Engineering: Understanding Steering Loops Through Real-World Examples
nrslib
6
7.3k
Other Decks in Programming
See All in Programming
全PRの83%がAIレビューだけでマージできるようになった開発組織はその後どうなったか
athug
0
630
使用 Meilisearch 建立新聞搜尋工具
johnroyer
0
190
ソフトウェア設計に溶けるインフラ ― AWS CDK のインフラ認識論
konokenj
3
710
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
470
AI時代の仕事技芸論〜ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ(スクフェス仙台 2026バージョン)
kuranuki
0
790
Android CLI
fornewid
0
190
これって Effect でできたのでは? / TSKaigi Mashup Kansai #2
susisu
0
120
【やさしく解説 設計編・中級 #1】一つの車に、運転手は一人 ~ある倉庫システムの事例から~
panda728
PRO
0
200
テーブルをDELETEした
yuzneri
0
130
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
330
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
430
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
820
Featured
See All Featured
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.5k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
650
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
330
Abbi's Birthday
coloredviolet
3
8.9k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
750
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
280
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
920
GraphQLとの向き合い方2022年版
quramy
50
15k
From π to Pie charts
rasagy
0
240
Producing Creativity
orderedlist
PRO
348
40k
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