Java | オブジェクト指向:クラス名の付け方

Java Java
スポンサーリンク

クラス名をつける前に知っておきたいこと

クラス名は、「このクラスは何者か」を一言で説明するラベルです。
クラス名だけで、そのクラスの役割や意味がある程度イメージできるのが理想です。

逆に言うと、クラス名があいまいだと

これはデータなのか?
ロジックを持つのか?
どんな場面で使うのか?

が全く見えてこなくなります。

クラス名は「設計そのもの」を言語化したものです。
だから、クラス名をちゃんと考えることは、オブジェクト指向設計そのものを鍛えることにつながります。


基本方針:クラス名は「名詞」で、そのクラスの正体を表す(重要)

何を表すクラスなのかを、日本語で一言にする

クラス名を決めるとき、まずいきなり英語で考えないで
「このクラスって、日本語で一言で言うと何?」
と自問してください。

例えば、こんなクラスを作ろうとしているとします。

「ユーザの名前・メールアドレス・ポイントを持っていて、自分のポイントを増やしたりできるやつ」

日本語で言えば「ユーザ」です。
だからクラス名は素直に User でいい。

「商品を複数入れておいて、合計金額を計算したりするやつ」
→ それは「カート」。
→ クラス名は Cart

「割引のルールを表すやつ」
→ 「割引ポリシー」。
→ クラス名は DiscountPolicy

この「日本語で一言にする作業」をサボると、
とりあえず Data, Info, Manager, Util のような、
何をしているのか分からない名前になりがちです。

クラス名は基本「名詞」か「名詞+役割」

クラス名は原則として「名詞」にします。

User, Order, Product, Cart, Invoice

または、「役割の名前」をつけるときは

PasswordEncoder (パスワードをエンコードする役)
MailSender (メールを送る役)
ReportGenerator (レポート生成役)

のように、「名詞+何者か」がはっきり分かる名前にします。

逆に、DoSomething, ProcessData のような「動詞中心」のクラス名は、
「それクラスじゃなくてメソッド名では?」と疑っていいです。


やりがちな悪いクラス名と、その直し方

「意味が薄い汎用名」パターン

初心者が一番やりがちなのが、こういう名前です。

UserData
UserInfo
CommonUtil
OrderManager
MainLogic

こういう名前は、具体的に何をしているのかが全く分かりません。

例えば UserData
本当に「ただのデータ入れ物(DTO)」なら、画面との境界で使うのはアリです。
でもドメインの中心にいる「ユーザ」を表すなら、
クラス名は User でいいし、
そこにビジネスルール(例:ポイントロジック・メール変更ルール)を持たせるべきです。

public class User {
    private String name;
    private String email;
    private int point;
    // 振る舞いもここに書く
}
Java

CommonUtilHelper も同じです。
そのクラスを見ただけでは、「何の役に立つクラスなのか」が全く想像できません。

もし「日付に関する処理」が中心なら DateTimeUtils
「文字列のバリデーション」が中心なら StringValidator

というふうに、そのクラスが扱う“話題”を名前に含めます。

「Manager」「Service」をつけすぎるパターン

UserManager
OrderService
ProductManager

これも注意が必要です。

本当に「複数のエンティティを管理して、あれこれ操作する“調整役”」ならまだしも、
実際は「なんとなくクラスっぽく見せるためにつけただけ」なことが多いです。

例えば UserManager

ユーザ登録
ユーザ削除
ポイント加算
メール送信

など何でもかんでも持っているなら、その名前は「ごまかし」です。

その中身を見て、本当にやっていることが
「ユーザの登録と取得だけ」なら UserRepository のほうが正直ですし、
「ユーザ登録のユースケース」なら UserRegistrationService のほうが分かりやすいです。

クラス名に Manager と付けたくなったら、

このクラスは何を管理していて、何をするのが主な仕事?

を自問して、もっと具体的な名前に変えられないか考えてみてください。


ドメイン(業務)の言葉をクラス名に持ち込む(重要なポイント)

現場で使っている言葉を、そのままクラス名にする

例えば、ホテル予約システムを作っているとします。

現場で飛んでいる言葉は

予約
キャンセル
チェックイン
チェックアウト
宿泊者
部屋タイプ

などですよね。

これをそのままクラス名にしていきます。

Reservation
CancellationPolicy
CheckIn(ユースケース名として)
Guest
RoomType

こうすると、「ドメインの会話」と「コード」の距離がぐっと近くなります。

仕様書に「チェックイン時に◯◯する」と書いてあったら、
CheckInCheckInService を探しに行けばよい。
請求書の話なら InvoiceBillingService を探せばよい。

逆に、SystemManager, MainService のような名前しかないと、
ドメインのどの話がどのクラスに対応しているかが分からなくなります。

技術用語よりドメイン用語を優先する

例えば「ユーザ情報を DB から取得する」クラスがあったとします。

技術寄り発想だと UserDaoUserJdbcRepository といった名前をつけたくなりますが、
ドメイン寄りに見るなら「ユーザの永続化を担当する」と捉えて UserRepository のほうが良いことが多いです。

Jdbc などの具体技術名は、「実装クラス」の名前に閉じ込めればよくて、

UserRepository(インターフェース)
JdbcUserRepository(実装)

のように分けると、ドメイン側は UserRepository だけ知っていれば済みます。

クラス名に「技術的な詳細」を書きすぎると、
後で技術を変えたくなったときに名前が嘘になります。


クラス名から「使い方」が見えるようにする

呼び出しコードを音読してみる

良いクラス名は、呼び出し側のコードを「文章」として読んだときに自然です。

例えば、次のどちらが読みやすいか感じてみてください。

UserManager um = new UserManager();
um.execute(u);
Java
UserRegistrationService registration = new UserRegistrationService();
registration.register(user);
Java

後者は日本語にすると

「ユーザ登録サービス」「ユーザを登録する」

と自然な文章になります。

クラス名とメソッド名をセットで設計するときは、
頭の中で

クラス名 変数 = ...;
変数.メソッド名(...);

を読んでみて、「日本語として違和感ないか」を確認してください。

OrderService service = ...;
service.place(order);

よりは

OrderService orderService = ...;
orderService.place(order);

のほうがまだマシですし、
さらに

OrderPlacer placer = ...;
placer.place(order);

くらいまで寄せられると、「注文を確定する役」というのがくっきり見えてきます。

クラス名自体に責務の範囲を刻む

ReportServiceMonthlySalesReportGeneratorでは、
後者のほうが「このクラスは月次売上レポートの生成だけをするんだな」と分かります。

もちろん、名前が長くなりすぎるのは考えものです。

MonthlySalesReportCsvFileGeneratorForMarketingDepartment

みたいな名前はやりすぎです。

けれども、責務がはっきりしているなら、
多少長くても「意味が具体的な名前」を優先したほうが読み手には親切です。


抽象クラス・インターフェースの名前のつけ方

インターフェースは「何ができるか」を名前にする

例えば「メールを送る」という能力を抽象化したい場合。

public interface MailSender {
    void send(String to, String subject, String body);
}
Java

MailSender は、「メールを送ることができるもの」です。
実装は用途に応じて

SmtpMailSender
ConsoleMailSender(テスト用に標準出力に出すだけ)
FakeMailSender(テストで何も送らずログだけ記録)

など、具体的なクラス名にします。

インターフェース側は「役割」、実装側は「具体的な手段」を表す名前、
と分けることが多いです。

DiscountPolicy(抽象:割引ポリシー)
RateDiscountPolicy(具体:率による割引)
AmountDiscountPolicy(具体:金額による割引)

なども典型的です。


実際のリネーム例で流れを掴む

Before

public class DataManager {

    public void doProcess(UserData data) {
        // ユーザ登録してメールを送る処理
    }
}
Java

このコードからだけでは、

何のデータを扱うのか
何をするクラスなのか

がまったく伝わりません。

After のイメージ

業務的には「ユーザ登録」だと分かっているので、
クラス名は UserRegistrationService にしてしまいます。

UserData は、もしドメインの中心なら User に。
画面からの入力の入れ物なら UserRegistrationRequest のような DTO 名に。

public class UserRegistrationService {

    public void register(User user) {
        // ユーザ登録してメールを送る処理
    }
}
Java

呼び出し側はこうなります。

UserRegistrationService registration = new UserRegistrationService();
registration.register(user);
Java

日本語で読むと「ユーザ登録サービス」「ユーザを登録する」。
役割も挙動も、名前からかなり想像しやすくなりました。

このように「クラス名を変えようとすると、中身の責務も自然と整理される」のが、
命名リファクタリングの面白いところです。


まとめ:クラス名をつけるときの自分への質問

クラス名を書く前・書いた後に、短く自問してみてください。

このクラスは、日本語で一言で言うと何者?
その一言は名詞になっているか?
ドメインの言葉(業務で使う用語)を使えているか?
「〜Manager」「〜Util」「〜Data」でごまかしていないか?
呼び出しコードを読んだとき、日本語として自然に読めるか?

ここで少しでもモヤッとしたら、そのクラス名は変える価値があります。

タイトルとURLをコピーしました