はじめに
最近、「現場で役立つシステム設計の原則」を読んでいるので、本書の中で自分が疑問に感じたポイントをQ&A形式で振り返ってみたいと思います。
この記事では、各セクションの簡単な説明の後に、[Q]で疑問に感じたこと、[A]で調べてわかったこと、そして[NOTE]で覚えておきたいことをまとめています。
なお、サンプルコードにJavaを使用していますが、言語を問わず広く有効な設計手法なので、他言語でも応用できる内容になっています。
それでは、第1〜2章を振り返りながら、一緒に「システム設計」について学んでいきましょう!
ドメインオブジェクト
「送料」クラスのように、業務で使われる用語に合わせて、その用語の関心事に対応するクラスをドメインオブジェクトと呼びます。
アプリケーションの対応領域(ドメイン)の関心事を記述したオブジェクトという意味です。
// 送料クラス
class ShippingCost {
static final int minimumForFree = 3000;
static final int cost = 500;
int basePrice;
ShippingCost(int basePrice) {
this.basePrice = basePrice;
}
int amount() {
if (basePrice < minimumForFree) return cost;
return 0;
}
}
このように業務の用語と、直接対応するドメインオブジェクトを用意することが、業務アプリケーションの変更を容易にするオブジェクト指向らしい設計のアプローチです。
[NOTE]
分析で発見した業務の構造とプログラムの構造が一致していれば、変更が楽で安全になります。
修正や拡張が必要になったとき、どこに何が書いてあるかも特定しやすくなります。
区分オブジェクト
列挙型を使って、区分ごとのロジックをわかりやすく整理するこの方法を区分オブジェクトと呼びます。
このように、区分定数の一覧を宣言する列挙型は、Java以外の言語でも用意されています。
enum FeeType {
adult(new AdultFee()),
child(new ChildFee()),
senior(new SeniorFee());
private Fee fee;
// Feeインターフェースを実装したどれかのクラスのオブジェクト
private FeeType(Fee fee) {
this.fee = fee; // 料金区分ごとのオブジェクトを設定する
}
Yen yen() {
return fee.yen();
}
String label() {
return fee.label();
}
}
このように料金区分に関するロジックを整理しておけば、区分名を指定して、区分ごとの料金を計算できます。
Enum
クラスの valueOf()
メソッドは、if
文を使わずにタイプ名から区分ごとのオブジェクトを取得できる便利で分かりやすい方法です。
Yen feeFor(String feeTypeName) {
FeeType feeType = FeeType.valueOf(feeTypeName); // たとえば、"adult"
return feeType.yen();
}
[NOTE]
区分定数を単なる定数ではなく、振る舞いを持ったオブジェクトとして表現します。
「振る舞いを持つ」というのは、メソッドを指定して判断/加工/計算を依頼できるという意味です。
この振る舞いを持った区分オブジェクトをうまく使うことで、区分ごとの if
文/ switch
文でごちゃごちゃしがちなコードをすっきりと見通しよく整理できます。
そして、区分ごとのロジックをそれぞれ別のクラスに独立させて整理することで、区分の追加や、区分ごとのロジックの変更が楽で安全になります。
おわりに
今回は、「現場で役立つシステム設計の原則」の第1~2章を題材に、自分が疑問に感じたポイントを紹介しました。
業務の概念をそのままコードに落とし込むことが、結果的に保守性や拡張性を高める設計につながっていくので、ぜひ一緒に意識していきましょう!
今後も読み進めながら、気づきがあればこうした形でまとめていきたいと思います!