[TypeScript] オブジェクト指向らしい設計にする方法
はじめに
この記事では、TypeScriptでオブジェクト指向らしい設計にする方法を解説します。
参考資料
1. 1つのメソッドのインデントは1つまで
1番深いインデントの処理をメソッドを抽出し、次のインデントをさらにメソッドに抽出するパターンです。
インデントは、1つの処理単位であり、その単位をメソッドとか、クラスに抽出して部品化すること
2. else句を使わない
else句はif文を複雑にして読みにくく、変更に対応しにくいです。
ガード節と早期リターンを組み込み、else句を回避する
function calculateDiscount(price: number): number | string {
// ガード節による入力値のチェックし、早期リターンを行う
if (price <= 0) {
return "価格は正の値でなければなりません";
}
// ガード節を通過した場合の処理
const discount: number = price * 0.1;
const discountedPrice: number = price - discount;
return discountedPrice;
}
3. 全てのプリミティブ型と文字列をラップする
数値や文字列を「判断」「加工」「計算」を行うロジックをデータを持つクラスに置くことでコードの重複が減り、変更の影響範囲を1つのクラスに閉じ込める事が出来る
プリミティブ型と文字列を引数として渡したり、メソッドの戻り値として使うと
ロジックがどこに書いてあるか分かりにくくなります。
ロジックと、そのロジックが使うプリミティブ型や文字列のデータがいつも同じクラスにまとまっていること
[Q] プリミティブ型とは?
[A] プログラミング言語において基本的なデータ型のことです。これらの型は、プログラムで使用されるデータの基本的な形式を定義します。一般的なプリミティブ型には、整数、浮動小数点数、文字、真偽値などがあります。
4. 1行につきドットは1つまで
ドットを使った複数のメソッドを連ねた文は、意図が分かりにくくなります。
同じ処理があちこちに重複した書かれる原因になる
このルールを実践する方法は、ドットの1つごとに説明用の変数に代入して別の文に分ける事です。
説明用の変数名で意図を明確化します
1つひとつの処理を独立すれば、メソッドの抽出やクラスによって、コードの再利用の機会も増えます
5. 名前を省略しない
オブジェクト指向は、利用者の関心事とソフトウェアのプログラム単位とを直接的に関連付ける技法です。
そのため、「クラス」「関数名」「変数名」が利用者の関心事に一致している事が大事なため、辞書が書かれている単語を使用する
6. すべてのエンティティを小さくする
データを持つクラスにロジックを移動し、そのクラスに処理を依頼するため、そのクラスを使う側のコードがシンプルになる。
インスタンス変数とメソッドの結びつき事にグルーピングしてクラスを抽出すれば、クラスは必然的に小さくなる
クラスが増えたら、パッケージでグルーピングする
長いメソッド、巨大なクラス、クラスの数が多いパッケージは設計が上手くっていない兆候です。
対象 | ガイドライン |
---|---|
メソッドの行数 | 3行を目標する。1行でもよい |
クラスの行数 | 50行を目標にする 100行以上は不可 |
パッケージのファイル数 | 10ファイル以内 |
7. 1つのクラスのインスタンス変数は2つまで
インスタンス変数とメソッドの関連付けを徹底するためのルールです。
インスタンス変数とメソッドが密接に結び付いたクラスは、
目的が単純で意図が明確です。
どこに何が書いてあるのかの特定がしやすく、変更の箇所とその影響範囲をクラスに閉じ込めやすいです。
インスタンス変数が増えると、クラスの意図がだんだんぼやけてきます。
8. ファーストクラスコレクションを使う
関連するデータとロジックを出来るだけ近くに置くのが鉄則です。
配列やコレクション操作は、コードが複雑になりやすく、バグが混入しやすい場所です。
そのようなコレクションをインスタンス変数に持つクラスに集めて管理する
対処の配列/コレクションを1つだけ持つ独立したクラスにする
9. 「getter 」「setter」「プロパティ」を使わない
「getter 」「setter」「プロパティ」は、データクラスのための設計パターンです
メソッドは、何らかの「判断」「加工」「計算」をしなければならない
インスタンス変数をそのまま返すだけの「getter 」を使わない
「setter」は、プログラムの挙動を不安定にしバグの原因になる
Discussion