Instantiate class by passing required parameter de

2019-06-13 16:45发布

问题:

I have a below enum class which has few fields in it stagePoolSize, prodPoolSize and enabled.

  public enum Type {
    process_caty(5, 8, false), process_misc1(5, 8, false), link_entry(5, 12, true);
    private final int stagePoolSize;
    private final int prodPoolSize;
    private final boolean enabled;

    private Type(int stagePoolSize, int prodPoolSize, boolean enabled) {
      this.stagePoolSize = stagePoolSize;
      this.prodPoolSize = prodPoolSize;
      this.enabled = enabled;
    }

    public int getStagePoolSize() {
      return stagePoolSize;
    }

    public int getProdPoolSize() {
      return prodPoolSize;
    }

    public boolean isEnabled() {
      return enabled;
    }

    @Override
    public String toString() {
      return name() + "=" + stagePoolSize + "=" + prodPoolSize + "=" + enabled;
    }
  }

And this is how I am using above enum to initialize my Handler class.

  private final List<Handler> handlers = new ArrayList<>();

  @PostConstruct
  public void postInit() {
    String datacenter = Utils.getDatacenter();

    for (Type consType : Type.values()) {
      if (!consType.isEnabled()) {
        continue;
      }
      int poolSize = Utils.isProd() ? consType.getProdPoolSize() : consType.getStagePoolSize();
      handlers.add(new Handler(consType, poolSize));
    }
  }

If any of the enum is enabled, then depending on which environment (whether Prod or Stage) we are in by checking with this call Utils.isProd(), we get it's poolSize and then use that poolSize to initialize Handler class.

Problem Statement:

Now I need to add few more enums in the same Type class but I need to do something different for them. Below are the enums I need to add:

abc_raw_pho
abc_raw_slq
abc_raw_lvk
abc_raw_pin_pho
abc_raw_pin_slq
abc_raw_pin_lvk

Here is what we need to do for above new enums:

  • It should only be used if the environment is Prod. And they will have some prodPool size value.
  • And also if we are in pho datanceter, then we should use enums that ends with pho. And if we are in slq datacenter then we should use enums that ends with slq. Similarly for lvk.

I can figure out which datacenter we are in by calling this method:

    String datacenter = Utils.getDatacenter();

Now how should I design my Type enum class so that my original enum works as it is which is already there and also my new enum with datacenter in the end works with the above conditions. So below is the requirement overall:

  • process_caty should be use both for Stage and Prod and it should use poolSize accordingly depending on what environment it is in.
  • process_misc1 should be use both for Stage and Prod and it should use poolSize accordingly depending on what environment it is in.
  • link_entry should be use both for Stage and Prod and it should use poolSize accordingly depending on what environment it is in.
  • abc_raw_pho should be use for Prod only but depending on which datacenter we are in and it should use poolSize for Prod only.
  • abc_raw_slq should be use for Prod only but depending on which datacenter we are in and it should use poolSize for Prod only.
  • abc_raw_lvk should be use for Prod only but depending on which datacenter we are in and it should use poolSize for Prod only.
  • abc_raw_pin_pho should be for Prod only but depending on which datacenter we are in and it should use poolSize for Prod only.
  • abc_raw_pin_slq should be for Prod only but depending on which datacenter we are in and it should use poolSize for Prod only.
  • abc_raw_pin_lvk should be for Prod only but depending on which datacenter we are in and it should use poolSize for Prod only.

回答1:

I would refactor your enum and break it down into smaller classes, introducing models for Environment, DataCenter and PoolSizes:

public enum Environment {PROD, STAGE}

public enum DataCenter {PHO, SLQ, LVK, NA /*Not applicable*/}

public class PoolSizes {

    public static final int SIZE_UNDEFINED = -1;

    private Map<Environment, Integer> environmentValues;

    public PoolSizes() {
        environmentValues = new HashMap<>();
    }

    public PoolSizes withStagePoolSize(int size) {
        environmentValues.put(Environment.STAGE, size);
        return this;
    }   

    public PoolSizes withProductionPoolSize(int size) {
        environmentValues.put(Environment.PROD, size);
        return this;
    }

    public int getPoolSize(Environment environment) {
        Integer size = environmentValues.get(environment);
        return size != null ? size : SIZE_UNDEFINED;            
    }        
}

The Type enum would then use these to simplify the logic for poolsize lookup and determining whether the type is enabled or not:

public enum Type {

    PROCESS_CATY(new PoolSizes().withStagePoolSize(5).withProductionPoolSize(8), 
        DataCenter.NA, false), 
    PROCESS_MISC1(new PoolSizes().withStagePoolSize(5).withProductionPoolSize(8), 
        DataCenter.NA, false), 
    LINK_ENTRY(new PoolSizes().withStagePoolSize(5).withProductionPoolSize(12), 
        DataCenter.NA, true),

    ABC_RAW_PHO(new PoolSizes().withProductionPoolSize(123), DataCenter.PHO, true),
    ABC_RAW_SLQ(new PoolSizes().withProductionPoolSize(123), DataCenter.SLQ, true),
    ABC_RAW_LVK(new PoolSizes().withProductionPoolSize(123), DataCenter.LVK, true),

    ABC_RAW_PIN_PHO(new PoolSizes().withProductionPoolSize(123), DataCenter.PHO, true),
    ABC_RAW_PIN_SLQ(new PoolSizes().withProductionPoolSize(123), DataCenter.SLQ, true),
    ABC_RAW_PIN_LVK(new PoolSizes().withProductionPoolSize(123), DataCenter.LVK, true);

    private final PoolSizes poolSizes;
    private final DataCenter dataCenter;
    private final boolean enabled;

    private Type(PoolSizes poolSizes, DataCenter dataCenter, boolean enabled) {
      this.poolSizes = poolSizes;
      this.dataCenter = dataCenter;
      this.enabled = enabled;
    }

    public int getPoolSize(Environment environment) {
      return poolSizes.getPoolSize(environment);
    }

    public DataCenter getDataCenter() {
        return this.dataCenter;
    }

    public boolean isEnabled(Environment environment, DataCenter dataCenter) {
      return enabled && poolSizes.getPoolSize(environment) != PoolSizes.SIZE_UNDEFINED 
              && (getDataCenter() == DataCenter.NA || getDataCenter() == dataCenter);
    }
  }

Finally, the postInit() method would become something like this:

public void postInit() {
    DataCenter dataCenter = Utils.getDataCenter();
    Environment environment = Utils.getEnvironment();

    for (Type consType : Type.values()) {
      if (!consType.isEnabled(dataCenter, environment)) {
        continue;
      }
      handlers.add(new Handler(consType, consType.getPoolSize(environment)));
    }
}