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
/←このスケジュール表に立ち向かう フロントエンド開発戦略 / A front-end development strategy to tackle a single-slash schedule.
nrslib
1
670
Pythonによるイベントソーシングへの挑戦と現状に対する考察 / Challenging Event Sourcing with Python and Reflections on the Current State
nrslib
3
1.5k
デザインシステムとコンポーネント指向によるフロントエンド開発プロセスの革新 / Innovation in Frontend Development Processes through Design Systems and Component-Oriented Architecture
nrslib
9
5.9k
さきがけから振り返るアーキテクチャ刷新 / Reflecting on the Architectural Renewal from the Vanguard
nrslib
6
2k
ぼっちを避けて楽しむためのアノテコノテ / Various Tips and Tricks to Avoid Loneliness and Have Fun
nrslib
3
2.4k
イベント駆動アーキテクチャ導入の手引きと共通の落とし穴 / Guide to Implementing Event-Driven Architecture and Common Pitfalls
nrslib
12
4.9k
CQRS+ES解体新書 / CQRS ES Disassembly Book
nrslib
7
2.9k
イベントストーミングによるオブジェクトモデリング・オブジェクト指向プログラミングの適用・開発プロセスの変遷・アーキテクチャの変革 / Object modeling with Event Storming.
nrslib
13
7k
Deep Dive 大規模システムアーキテクチャ/開発組織エンジニアリング / Deep Dive Large-Scale System Architecture, Development Organization Engineering
nrslib
16
3.6k
Other Decks in Programming
See All in Programming
リアーキテクチャxDDD 1年間の取り組みと進化
hsawaji
1
220
광고 소재 심사 과정에 AI를 도입하여 광고 서비스 생산성 향상시키기
kakao
PRO
0
170
OnlineTestConf: Test Automation Friend or Foe
maaretp
0
110
.NET のための通信フレームワーク MagicOnion 入門 / Introduction to MagicOnion
mayuki
1
1.4k
PHP でアセンブリ言語のように書く技術
memory1994
PRO
1
170
エンジニアとして関わる要件と仕様(公開用)
murabayashi
0
280
LLM生成文章の精度評価自動化とプロンプトチューニングの効率化について
layerx
PRO
2
190
どうして僕の作ったクラスが手続き型と言われなきゃいけないんですか
akikogoto
1
120
Snowflake x dbtで作るセキュアでアジャイルなデータ基盤
tsoshiro
2
520
Better Code Design in PHP
afilina
PRO
0
120
みんなでプロポーザルを書いてみた
yuriko1211
0
260
Tauriでネイティブアプリを作りたい
tsucchinoko
0
370
Featured
See All Featured
The Cost Of JavaScript in 2023
addyosmani
45
6.7k
Optimizing for Happiness
mojombo
376
70k
GraphQLとの向き合い方2022年版
quramy
43
13k
Typedesign – Prime Four
hannesfritz
40
2.4k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
26
2.1k
Designing for humans not robots
tammielis
250
25k
Docker and Python
trallard
40
3.1k
Rails Girls Zürich Keynote
gr2m
94
13k
Building Adaptive Systems
keathley
38
2.3k
Documentation Writing (for coders)
carmenintech
65
4.4k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.8k
Optimising Largest Contentful Paint
csswizardry
33
2.9k
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