简体   繁体   中英

Can the 'Strategy pattern' be implemented using Java annotations?

I want to use the Strategy Pattern to implement some bespoke formatting behaviour to members in third party classes. I want the third party to have to do no more than annotate the class members to indicate whether they should use format strategy (A, B or C) and then call my 'format' function with an instance of their class. My format function should then use the annotations to identify the members requiring formatting and which of my format strategies to use.

public class ThirdPartyClass
{
    @FormatStrategy(fmt=unsigned8,offset=0)
    int memberA;

    @FormatStrategy(fmt=unsigned16,offset=1)
    int memberB;

    @FormatStrategy(fmt=unsigned16,offset=3)
    int memberB;
}

In a perfect world I would like Java annotations to support both inheritance and methods but this seems not to be the case. So my question is, in the absence of either of these what is a nice way of implementing this while still only touching the third party class with annotations?

Regards

I believe this can be done with annotations, exactly the way you have proposed it. This would be a sample implementation, it also uses the AbstractFactory pattern:

class ThirdPartyClass {
    @FormatStrategy(fmt="unsigned8",offset=0)
    int memberA;

    @FormatStrategy(fmt="unsigned16",offset=1)
    int memberB;

    @FormatStrategy(fmt="unsigned16",offset=3)
    int memberC;
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FormatStrategy{
    String fmt() default "unsigned8";
    int offset()default 0;
}

interface FormattingStrategy{
    String formatNumber(int number);
}

class BasicFormattingStrategy implements FormattingStrategy{
    private String fmt;
    private int offset;

    private BasicFormattingStrategy(String fmt, int offset) {
        this.fmt = fmt;
        this.offset = offset;
    }

    @Override
    public String formatNumber(int number) {
        // do formatting here
        return "formatted number";
    }

}

interface StrategyFactory{
    FormattingStrategy getStrategy(FormatStrategy fmtStrategy);
}

class DefaultStrategyFactory implements StrategyFactory{

    @Override
    public FormattingStrategy getStrategy(FormatStrategy fmtStrategy) {
        // right now only one strategy implementation exists, but may have many.
        return new BasicFormattingStrategy(fmtStrategy.fmt(), fmtStrategy.offset());
    }

}

Here would be the code that actually uses the strategy:

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException{
    StrategyFactory factory = new DefaultStrategyFactory();
    ThirdPartyClass obj = new ThirdPartyClass();
    Class<ThirdPartyClass> clazz = (Class<ThirdPartyClass>) obj.getClass();
    for(Field field : clazz.getDeclaredFields()){
        FormatStrategy fmtStrategy = field.getAnnotation(FormatStrategy.class);
        if(fmtStrategy != null){
           FormattingStrategy strategy = factory.getStrategy(fmtStrategy);
           String formattedNumber = strategy.formatNumber(field.getInt(obj));
           // use the formatted number
        }
    }
}

Obviously, you'll want to do actual exception handling/error checking.

I assume you're processing this class with reflection, as you have no idea what fields they're going to have declared?

ie you're going to have something like:

for (Field f : inputInstance.getClass().getDeclaredFields()) {
  FormatStrategy fs = f.getAnnotation(FormatStrategy.class);
  getImplementationOf(fs).run();
}

Which part are you concerned with? The implementation of the getImplementationOf() method? This would be a standard "factory"-like method for strategies? As you've observed there's no way to directly encode the logic into the annotation itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM