1

I have the following classes

public class MyCustomFactory extends SomeOther3rdPartyFactory {

    // Return our custom behaviour for the 'string' type
    @Override
    public StringType stringType() {
        return new MyCustomStringType();
    }

    // Return our custom behaviour for the 'int' type
    @Override
    public IntType intType() {
        return new MyCustomIntType();
    }

    // same for boolean, array, object etc
}

Now, for example, the custom type classes:

public class MyCustomStringType extends StringType {
    @Override
    public void enrichWithProperty(final SomePropertyObject prop) {
        super.enrichWithProperty(prop);

        if (prop.getSomeAttribute("attribute01")) {
            this.doSomething();
            this.doSomethingElse();
        }

        if (prop.getSomeAttribute("attribute02")) {
            this.doSomethingYetAgain();
        }

        // other properties and actions
    }
}

But each custom type class like the string one above might have exactly the same if (prop.getSomeAttribute("blah")) { // same thing; }

Suppose I was to add another attribute, is there a nice way I can avoid having to duplicate if statements in each custom type class that needs it? I can move each if statement to utility class but I still need to add the call to the method in the utility class. I think we can do better.

8
  • So depending on whether prop has some attribute you want to do different things or the same things? Commented Mar 2, 2018 at 16:26
  • They will all do the same thing if the prop has some attribute Commented Mar 2, 2018 at 16:28
  • 1
    I would iterate over all of the attributes of prop, and I would look each one up in a Map<Attribute, ThingThatKnowsWhatToDoAboutIt>. Commented Mar 2, 2018 at 16:28
  • Maybe update your question then to say this.doSomething() for all examples. It looks like you are calling different methods. Commented Mar 2, 2018 at 16:28
  • And if they all call the same method then anyhow why not just do if(prop.getSomeAttribute("blah") || if(prop.getSomeAttribute("bleh"))? Commented Mar 2, 2018 at 16:30

1 Answer 1

1

You can create Map<String, Consumer<MyCustomStringType>>, where the key is your attribute name and value is the method call.

public class MyCustomStringType extends StringType {

    private final Map<String, Cosnumer<MyCustomStringType>> map = new HashMap<>();

    {
        map.put("attribute01", o -> {o.doSomething(); o.doSomethingElse();});
        map.put("attribute02", MyCustomStringType::doSomethingYetAgain);
        // other properties and actions
    }

    @Override
    public void enrichWithProperty(final SomePropertyObject prop) {
        super.enrichWithProperty(prop);

        map.entrySet().stream()
            .filter(entry -> prop.getSomeAttribute(entry.getKey()))
            .forEach(entry -> entry.getValue().accept(MyCustomStringType.this));
    }
}

Depending on how you initialise this class (and whether this map is always the same), you might be able to turn in into static final immutable map.

I would also recommend naming it better, but a lot here depends on your domain and what this map and loop actually do.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks. This map needs to be global and shared between each custom type class. We then need another map which maps the custom type to the attributes being used. And then each enrichWithProperty() for each custom class should look the same - just iterating over these maps. So the logic should be 'If this attribute is enabled for this custom type, then fetch the actions for this attribute from the other map and perform them'. I realise I have shot myself in the foot with this example because in my real problem, the 'attribute' isn't a string but an annotation.
How does your if-statement look like if you have annotations? And for the global map, you can add another .filter() to filter by current class (you can make value to be a composite object - consumer plus something else that you can use in second .filter())
It looks like SomeAnnotation annotationInfo = prop.getAnnotationInfo(SomeAnnotation.class); if (annotationInfo != null) { this.setSomething(true); this.setSize(annotationInfo.sz()); }
@artvandelay Then you can put SomeAnnotation.class as a key in your map and modify the filter() method accordingly.
Thanks. So it would be Map<Class<?>, Consumer<ParentType>> but the lambda (Consumer function) needs the instance of annotation from the prop.getAnnotationInfo(SomeAnnotation.class) in most cases.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.