はじめに
クラス設計の理論を学んでいる際に表題の手法を知ったので、今回はこれを記事にしてみたいと思います。
リファクタリング前
まずは以下のコード見てみましょう。
class GiftPoint {
static const int _minPoint = 0;
final int value;
GiftPoint(this.value) {
if (value < _minPoint) {
throw ArgumentError('GiftPoint value cannot be less than $_minPoint');
}
}
}
上記のようなポイントオブジェクトの生成ロジックがあったとします。
書き方としては一般的であり、マイナス値を許さない処理にもなっていますね。
一見するとシンプルで良くできたものですが、メンテナンス性の観点では少し課題があります。
と言うのも、
final standardMemberShipPoint = GiftPoint(3000);
final premiumMemberShipPoint = GiftPoint(5000);
こういった用途別のオブジェクト生成に対応し切れてはいないからです。
上記のコードでもオブジェクト自体は生成できますが、こういったシーン別のオブジェクトはいろんな場面で頻繁に用いられ、
その度に同じポイントを付与するようにコードを確認する必要が生まれてしまいます。
editorによっては全体検索と一括変換の機能を備えているものもありますが、プログラムとして同じポイントを担保するように設計できるのであれば、それに越したことはありません。
リファクタリング後
そこで、上記ニーズを踏まえて以下のようにリファクタリングしてみましょう。
class GiftPoint {
static const int _minPoint = 0;
static const int _standardMembershipPoint = 3000;
static const int _premiumMembershipPoint = 5000;
final int value;
/// 用途別にポイントを生成するために、以下の処理は private constructor を使用
GiftPoint._(this.value);
/// 用途別にポイントを生成するために、以下の処理は private factory constructor を使用
factory GiftPoint._create(int value) {
if (value < _minPoint) {
throw ArgumentError('GiftPoint value cannot be less than $_minPoint');
}
return GiftPoint._(value);
}
factory GiftPoint.standardMembership() {
return GiftPoint._create(_standardMembershipPoint);
}
factory GiftPoint.premiumMembership() {
return GiftPoint._create(_premiumMembershipPoint);
}
}
上記コードは通常のコンストラクタとマイナス値排除のコンストラクタをprivateにして外部からは呼べないようにしています。
これにより外部との窓口を、
final standardMemberShipPoint = GiftPoint.standardMembership();
final premiumMemberShipPoint = GiftPoint.premiumMembership();
このようなコードに一本化することができます。
窓口を用途別に閉じた設計にする事で、用途別のポイントオブジェクトのポイントは常に同じになり、
変な値が混入するリスクやその調査を削減することができるようになりました。
参考