HiveBrain v1.2.0
Get Started
← Back to all entries
principlejavaModerate

Strategy pattern instances based on enums

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
instancesbasedstrategyenumspattern

Problem

I have a view which takes a DataPresenterStrategy instance to retrieve the proper text out of some data:

public interface DataPresenterStrategy {

    String getDisplayString(Data data);

    String getUnit();
}

public class DistanceStrategy implements DataPresenterStrategy {

    @Override
    public String getDisplayString(Data data) {
        return data.getDistance();
    }

    @Override
    public String getUnit() {
         return "m";
    }
}

public class PowerStrategy implements DataPresenterStrategy {

    @Override
    public String getDisplayString(Data data) {
        return data.getPower();
    }

    @Override
    public String getUnit() {
         return "W";
    }
}


Based on some enum, I know which DataPresenterStrategy to create:

enum DataPresenterStrategyType { DISTANCE, POWER }

DataPresenterStrategy toStrategy(StrategyType type) {
    switch(type) {
        case DISTANCE:
            return new DistanceStrategy();
        case POWER:
            return new PowerStrategy();
    }
}


Obviously, this is simplified. In my actual code I have 25 of those Strategy classes.
Is there a better way to do this DataPresenterStrategy instance creation?

Usage in views:

public interface DataPresenter {
    void setDataPresenterStrategy(DataPresenterStrategy strategy);
}

public class DataView implements DataPresenter {

    private DataPresenterStrategy mDataPresenterStrategy;

    @Override
    public void setDataPresenterStrategy(DataPresenterStrategy strategy) {
        mDataPresenterStrategy = strategy;
    }

}

public class MyApplication {

    private DataPresenter[] mDataPresenters;

    public void setDataPresenterStrategy(int dataPresenterIndex, DataPresenterStrategyType type) {
        switch (type)
          /* (...) */
    }

}


setDataPresenterStrategy(int, DataPresenterStrategyType) is called when a user selects an item from a spinner:

```
class MyOnItemSelectedListener implements OnItemSelectedListener

Solution

Another way to do the instance creation would be to give each type a constructor reference for the strategy it corresponds to.

enum DataPresenterStrategyType { 
    DISTANCE(DistanceStrategy::new), POWER(PowerStrategy::new);
    private final Supplier constructor;

    DataPresenterStrategyType(Supplier constructor){
        this.constructor = constructor;
    }

    DataPresenterStrategy newStrategy() {
        return constructor.get();
    }
}


The main advantages I see for this way are the compile time safety that each type has a Supplier and that you don't need to look for all the switch statements in your project to add cases if you add a new strategy type.

If not all of the constructors of your strategies take the same arguments you can replace the constructor reference with a lambda.

If you don't have access to Java 8, you can accomplish the same thing more verbosely with an anonymous class instead of the constructor reference, or you could make newStrategy() an abstract method and implement it in each type.

Code Snippets

enum DataPresenterStrategyType { 
    DISTANCE(DistanceStrategy::new), POWER(PowerStrategy::new);
    private final Supplier<DataPresenterStrategy> constructor;

    DataPresenterStrategyType(Supplier<DataPresenterStrategy> constructor){
        this.constructor = constructor;
    }

    DataPresenterStrategy newStrategy() {
        return constructor.get();
    }
}

Context

StackExchange Code Review Q#58489, answer score: 10

Revisions (0)

No revisions yet.