How to implement command pattern via CDI?

2019-03-31 10:14发布

I am newbie in CDI and a little bit confused. I have the following problem. We have class Action. And we have wrapper class that keeps all Action objects in hashmap. Something like this.

class TestAction implements Action{
  @EJB
  private MyBean bean; 
  public void doSomething(){
    //here we do something with injected EJB
  }
}

class Foo {
   private HashMap<String, Action> hm;
   public void execute (String action){
   this.hm.get(action).doSomething();    
 }    
}

When I don't use CDI - everything is ok. But I need to use it. So, as I understand I must create all my actions via cdi container otherwise CDI container can't inject managed beans into them. So my question what is the best way to implement command pattern via CDI?

EDITED: I read Dependency Injection by Dhanji R. Prasanna, Weld-reference(WR), JavaEE7 tutorial (CDI part) - don't recommend to read the last. After thinking a little bit I understood that I need to inject HashMap. Besides, I understood that I have to use producer methods. Ok. I said. Finally I got it. So I wrote the following producer method:

@ApplicationScoped
public class ActionMapFactory {
    @Produces @Preffered
    public HashMap<String, Action> getHashMap(){
    HashMap<String, Action> hm=new HashMap<>();
     if (...){
     hm.put("save",new SaveAction());
     }
     return hm;
    }
}

From WR:

There's one potential problem with the code above. The implementations of are instantiated using the Java new operator. Objects instantiated directly by the application can't take advantage of dependency injection and don't have interceptors.

I have read the solution from WR, but what should I do if I have dozens of actions and a lot child classes of Foo?

1条回答
地球回转人心会变
2楼-- · 2019-03-31 10:20

You could avoid new by injecting all actions into ActionMapFactory and populate the HashMap at the producer method:

@ApplicationScoped
public class ActionMapFactory {

    @Inject
    private SaveAction saveAction;

    @Inject
    private DeleteAction deleteAction;

    // And so on

    @Produces @Preffered
    public HashMap<String, Action> getHashMap() {
        Map<String, Action> hm = new HashMap<>();
        hm.put("save", saveAction);
        hm.put("delete", deleteAction);
        return hm;
    }
}

If you don't want to keep those Action instances as attributes, do a constructor injection:

private Map<String, Action> actionMap;

// This is part of the CDI bean contract
protected ActionMapFactory() {}

@Inject
public ActionMapFactory(SaveAction saveAction, DeleteAction deleteAction) {
    actionMap = new HashMap<>();
    actionMap.put("save", saveAction);
    actionMap.put("delete", deleteAction);
}

@Produces @Preffered
public HashMap<String, Action> getHashMap() {
    return actionMap;
}
查看更多
登录 后发表回答