社内でよく聞く声です。
「また同じ計算処理を書かなきゃいけない…」
「CommonUtil に入れすぎて探しにくくなってる」
「でも、他に置き場もないし…」
共通化の善意が、知らず知らずのうちに別の問題を生むことがあります。
典型的なのが “状態を持たない処理を何でもかんでもクラスに入れてしまう” パターンです。
便利クラス依存の問題点
CommonUtil や StringUtils など、便利そうだからと集めたクラスは、次のような状態になりがちです。
- クラスが肥大化し、何がどこにあるかわからなくなる
- 使いたいメソッドが探しづらく、再利用性が下がる
- 意図が曖昧で、レビュー時に説明が必要
- stateless な処理なのに
newされる
こうした問題を整理するのに 拡張メソッド が有効です。
拡張メソッドとは
既存の型に自然な形で処理を生やせる仕組みです。
- 元のクラスを変更せず追加可能
- 状態を持たない小さな処理に向く
- 型に紐づくことで可読性が上がる
例: 文字列の Normalize
public static class StringExtensions
{
public static string Normalize(this string s)
{
return s.Trim().ToUpper();
}
}
// 使い方
" hello ".Normalize(); // "HELLO"
new も不要で、ユーティリティクラスも不要です。
拡張メソッドが有効なケース
- 状態を持たない処理
- 自然に型に属する処理(int, string, DateTime など)
- 複数箇所で汎用的に使われる処理
- Helper クラスにまとめると置き場に困る処理
アンチパターンの整理
便利クラスにまとめすぎる
public class StringUtils
{
public string Normalize(string s) { … }
public string Reverse(string s) { … }
public bool IsNullOrEmpty(string s) { … }
}
- 型との距離が遠く、認知コストが高い
- どの処理がどこにあるかわかりにくい
状態なしなのにインスタンス変数を持たせる
public class Calculator
{
private int lastResult;
public int Add(int a, int b) { lastResult = a + b; return lastResult; }
}
- クラスの責務が曖昧
- インスタンス生成が必要でテストが面倒
- 共通化したい処理なのに扱いづらい
拡張メソッドで整理するとこうなる
public static class CalculatorExtensions
{
public static int Add(this int a, int b) => a + b;
public static int Multiply(this int a, int b) => a * b;
}
// 利用側
3.Add(5); // 8
3.Multiply(5); // 15
- インスタンス不要
- クラス肥大化なし
- 型に紐づく処理で意図が明確
- 再利用性が自然と高まる
まとめ・注意点
- 状態を持たない処理は拡張メソッドに整理すると見通しがよくなる
- 不要な共通クラスを減らせる
- 既存型を壊さず自然に処理を追加できる
注意:
- 過剰に使うとメソッドが散乱する
- 状態を持つ処理には向かない
拡張メソッドは “散らばりやすい小さな処理を型に戻す整理道具” として活用するのがベストです。