CDIを使用したプロジェクトがあります。状態のリストを持つコンテナマネージドサービスクラス。
@ApplicationScoped
public class StateService {
@Inject
MailService mailService;
//Inject some other stuff
private Map<String, State> state = new HashMap<String, State>();
public void makeStateTransition(StateChange stateChange) {
State currentState = state.get(stateChange.getKey());
switch (currentState.stateType) {
case STATE1:
handleState1Transition(stateChange);
case STATE2:
handleState2Transition(stateChange);
case STATE3:
handleState3Transition(stateChange);
}
}
private void handleState1Transition(StateChange stateChange) {
//Do some stuff to handle state and use injected mailsender to send some email
mailService.sendEmail("Send some email");
//if some criteria is right create a new state and set it in the map
State newState = new State();
//Set some variable
state.put(stateChange.getKey(), newState);
}
private void handleState2Transition(StateChange stateChange) {
//Do stuff similar to above, maybe use other injected fields
}
private void handleState3Transition(StateChange stateChange) {
//Do stuff similar to above
}
}
public class State {
public enum StateType {
STATE1, STATE2, STATE3
}
public StateType stateType;
//Bunch of other properties
}
これはひどく手続き的であることが判明しました。私はそれをよりOOにするためにリファクタリングしました。
@ApplicationScoped
public class StateService {
@Inject
MailService mailSerice;
//Inject some other stuff
private Map<String, State> state = new HashMap<String, State>();
public void makeStateTransition(StateChange stateChange) {
State currentState = state.get(stateChange.getKey());
State newState = currentState.handleStateChange(stateChange, mailService);
state.put(stateChange.getKey(), newState);
}
}
これで、StateServiceはすべての状態遷移を知る必要がなくなります
public abstract class State {
//Some protected fields shared by all states
public abstract State handleStateChange(StateChange stateChange, MailService mailService);
}
public class SomeState extends State {
//Some properties specific to this state
public State handleStateChange(StateChange stateChange, MailService mailSerice) {
//Do some stuff to handle state and use injected mailsender to send some email
mailSerice.sendEmail("Send some email");
return new SomeOtherState();
}
}
これにより、特に可能な状態の数が増えるにつれて、コードがはるかに優れたものになります。問題は、挿入されたメール送信者をそれを必要とする正しい状態にすることです。いくつかの州はそれを必要としないかもしれませんし、他の州は何か他のものを必要とするかもしれません。状態はコンテナによって作成されないため、インジェクション自体を使用することはできません。状態のコンストラクターで注入されたフィールドを渡すことは可能ですが、注入されたオブジェクトはアンマネージ状態内で「古くなる」可能性がありますか?
私はそれをメソッド呼び出しの引数として送信することにしました。そうすれば、常に「新鮮」であるはずです。多くのインジェクションを引数として送信する必要があり、何らかの形で間違っていると感じる場合は、非常に面倒です。
この例では、状態オブジェクトに必要な注入されたリソースを処理する方法をどのように提案しますか?
クラス内のスレッドの問題は無視してください。