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.9k
オブジェクト指向 パラメータ多相・実装継承 / OOP3
勉強会での登壇用資料です。
オブジェクト指向のパラメータ多相と実装継承 についての解説です。
https://nrslib.com
nrs
October 28, 2018
Tweet
Share
More Decks by nrs
See All by nrs
イベントストーミング図からコードへの変換手順 / Procedure for Converting Event Storming Diagrams to Code
nrslib
1
500
Javaのルールをねじ曲げろ!禁断の操作とその代償から学ぶメタプログラミング入門 / A Guide to Metaprogramming: Lessons from Forbidden Techniques and Their Price
nrslib
3
2k
コードに語らせよう――自己ドキュメント化が内包する楽しさについて / Let the Code Speak
nrslib
6
1.5k
ドメイン駆動設計とXPで支える子どもの未来 / Domain-Driven Design and XP Supporting Children's Future
nrslib
0
400
設計の本質:コード、システム、そして組織へ / The Essence of Design: To Code, Systems, and Organizations
nrslib
10
4.1k
アーキテクトと美学 / Architecture and Aesthetics
nrslib
14
3.6k
PHPで学ぶプログラミングの教訓 / Lessons in Programming Learned through PHP
nrslib
5
1.3k
/←このスケジュール表に立ち向かう フロントエンド開発戦略 / A front-end development strategy to tackle a single-slash schedule.
nrslib
1
890
Pythonによるイベントソーシングへの挑戦と現状に対する考察 / Challenging Event Sourcing with Python and Reflections on the Current State
nrslib
3
2.5k
Other Decks in Programming
See All in Programming
Team operations that are not burdened by SRE
kazatohiei
1
260
Result型で“失敗”を型にするPHPコードの書き方
kajitack
4
520
Hypervel - A Coroutine Framework for Laravel Artisans
albertcht
1
110
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
48
31k
「ElixirでIoT!!」のこれまでとこれから
takasehideki
0
370
PicoRuby on Rails
makicamel
2
110
Google Agent Development Kit でLINE Botを作ってみた
ymd65536
2
200
型付きアクターモデルがもたらす分散シミュレーションの未来
piyo7
0
810
技術同人誌をMCP Serverにしてみた
74th
1
440
Bytecode Manipulation 으로 생산성 높이기
bigstark
2
380
A2A プロトコルを試してみる
azukiazusa1
2
1.2k
『自分のデータだけ見せたい!』を叶える──Laravel × Casbin で複雑権限をスッキリ解きほぐす 25 分
akitotsukahara
1
580
Featured
See All Featured
A designer walks into a library…
pauljervisheath
207
24k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
Rails Girls Zürich Keynote
gr2m
94
14k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.5k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
138
34k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
35
2.4k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.8k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
30
2.1k
For a Future-Friendly Web
brad_frost
179
9.8k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
32
2.3k
Producing Creativity
orderedlist
PRO
346
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