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.6k
オブジェクト指向 パラメータ多相・実装継承 / OOP3
勉強会での登壇用資料です。
オブジェクト指向のパラメータ多相と実装継承 についての解説です。
https://nrslib.com
nrs
October 28, 2018
Tweet
Share
More Decks by nrs
See All by nrs
PHPで学ぶプログラミングの教訓 / Lessons in Programming Learned through PHP
nrslib
4
1k
/←このスケジュール表に立ち向かう フロントエンド開発戦略 / A front-end development strategy to tackle a single-slash schedule.
nrslib
1
750
Pythonによるイベントソーシングへの挑戦と現状に対する考察 / Challenging Event Sourcing with Python and Reflections on the Current State
nrslib
3
1.7k
デザインシステムとコンポーネント指向によるフロントエンド開発プロセスの革新 / Innovation in Frontend Development Processes through Design Systems and Component-Oriented Architecture
nrslib
9
6.2k
さきがけから振り返るアーキテクチャ刷新 / Reflecting on the Architectural Renewal from the Vanguard
nrslib
8
2.3k
ぼっちを避けて楽しむためのアノテコノテ / Various Tips and Tricks to Avoid Loneliness and Have Fun
nrslib
3
2.6k
イベント駆動アーキテクチャ導入の手引きと共通の落とし穴 / Guide to Implementing Event-Driven Architecture and Common Pitfalls
nrslib
12
5k
CQRS+ES解体新書 / CQRS ES Disassembly Book
nrslib
8
3.1k
イベントストーミングによるオブジェクトモデリング・オブジェクト指向プログラミングの適用・開発プロセスの変遷・アーキテクチャの変革 / Object modeling with Event Storming.
nrslib
13
7.3k
Other Decks in Programming
See All in Programming
Androidアプリの One Experience リリース
nein37
0
720
traP の部内 ISUCON とそれを支えるポータル / PISCON Portal
ikura_hamu
0
130
Androidアプリのモジュール分割における:x:commonを考える
okuzawats
1
260
20年もののレガシープロダクトに 0からPHPStanを入れるまで / phpcon2024
hirobe1999
0
980
QA環境で誰でも自由自在に現在時刻を操って検証できるようにした話
kalibora
1
110
各クラウドサービスにおける.NETの対応と見解
ymd65536
0
230
PHPUnitしか使ってこなかった 一般PHPerがPestに乗り換えた実録
mashirou1234
0
390
Go の GC の不得意な部分を克服したい
taiyow
3
980
ChatGPT とつくる PHP で OS 実装
memory1994
PRO
3
160
生成AIでGitHubソースコード取得して仕様書を作成
shukob
0
600
アクターシステムに頼らずEvent Sourcingする方法について
j5ik2o
6
670
非ブラウザランタイムとWeb標準 / Non-Browser Runtimes and Web Standards
petamoriken
0
410
Featured
See All Featured
Making the Leap to Tech Lead
cromwellryan
133
9k
RailsConf 2023
tenderlove
29
960
Scaling GitHub
holman
459
140k
Visualization
eitanlees
146
15k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.6k
Building Applications with DynamoDB
mza
92
6.1k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
97
17k
GraphQLとの向き合い方2022年版
quramy
44
13k
A Philosophy of Restraint
colly
203
16k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
33
2.7k
Automating Front-end Workflow
addyosmani
1366
200k
Raft: Consensus for Rubyists
vanstee
137
6.7k
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