かねがねから私はJavaのDIを信奉する人々を信じていなかったのだが、決定的なクソ仕様を発見したので、嬉々としてご報告する。
ソースがこんな感じになっているとする。パッケージが異なる同名のクラスね。
package org.abc.def; @Component public class Xyz extends BaseX { package org.abc.efg; @Component public class Xyz extends BaseX {
これ、エラーになってプログラムは起動すらしません(ConflictingBeanDefinitionException)。component scanにゴテゴテに書けばどうにかなる可能性もあるけど、こんなんウンコでしょう。ネームスペースのことを理解していないんですよこいつら。パッケージが違ってクラス名が一緒なんてそこら中に転がってることでしょう? java.util.Optionalとcom.google.common.base.Optionalとか、タイムスタンプ系の各種DateだのTimestampだのTimeStampだのとか(すでに忘れてるけど、要するにたくさんある)。それはDIの世界では決して許されない。
何かの対象A,B,Cがあって、「作成」「削除」「更新」の操作についていろいろ書こうと思うでしょう? 操作と対象ごとに別々のクラスにして、こんな感じのパッケージ/クラスにしようと思うと。まあよくあるケースではないかと思いますが。
作成 | 更新 | 削除 | |
A | org.abc.create.A | org.abc.modify.A | org.abc.remove.A |
B | org.abc.create.B | org.abc.modify.B | org.abc.remove.B |
C | org.abc.create.C | org.abc.modify.C | org.abc.remove.C |
わかると思いますが、これでは動かせないんですね。ApplicationContext作る時点で落ちるから。
だいたいDI好きな奴らもクラスの差し替えなんて滅多にしない。どうせ@AutowiredするときやgetBean()するときにクラス名は一意に決まってるわけだから、ダブって判断できないケースなんてほとんどないにも関わらず、ですよ??
どうすればいいのかというと、、、
- AやBの中にcreateやらremoveやらmodifyを入れる
- 規模が小さければこれで通用するが、複雑になってくると困る
- 対象が同一なだけで共通する処理がほとんどない場合、こうするメリットがない
- CreateA, ModifyA, RemoveAみたいなクラス名にする
- これはJavaの人が好んで使う方法で、ネームスペースを使わずに長大なシンボルやクラス名を作って満足するという、悪魔に魅入られたやり方
- 言語仕様にパッケージ作って区別できるようにした配慮を完全無視
- まあパッケージ自体使いにくいから私も好きではないんだけど
- コンポーネントの引数で別の名前を書く
- 次善の方法
- @Component(“blablabla”)みたいな
- ただ無駄な記述が増えるよね。文字数で給料が出る人のための、Java的な解決方法でもある
- @Primaryとかも効くのかな? その辺の動作はよく分かってないですが
- DIを使わずに書く
- これが最良な方法です
- まあDIさえなければJavaは数倍マシになりますよ
- Context作ってgetBean()なんて無駄な処理を書かずにnewできるようになるし、@Componentつけ忘れてcommitした奴に腹を立てることもなくなる!