2
\$\begingroup\$

I have a Type class that will have many instances. I get the instances from a web service. The Type class has a code instance field that uniquely ids an instance:

@Data
@AllArgsConstructor
public class Type {

 private String code;

}

Ten of these instances identify a special type. I have several places where I need to check if a Type is one of these special types:

aType.equals(new Type("specialType1")) || aType.equals(new Type("specialType2")) ||...

In other places, I need to find where aType is not a special type. To centralize these specialized types and the check, I put it in the Type class as follows:

@Data
@AllArgsConstructor
public class Type {
 
  private static final List<Type> specialTypes = Arrays.asList(new Type("specialType1"),...);
  private String code;

  public boolean isSpecialType() {
    return specialTypes.contains(this);
  }
}

Should specialTypes and the logic to compare a type to special types be in the Type class? Or would this type of logic be better in a service class? Should the special types be defined as enums?

Update

Type instances are created via use of open feign:

import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(name="type-service")
public interface TypeClient {

   @GetMapping("/type")
   List<Type> getTypes();
}
\$\endgroup\$
6
  • 1
    \$\begingroup\$ Why are subclasses not an option? \$\endgroup\$ Commented Sep 14, 2020 at 18:10
  • \$\begingroup\$ It could be. Open feign is creating the Type instances. (I updated the OP.) I'm not sure how feign would know to create a Type instance versus a SpecialType extends Type instance. \$\endgroup\$ Commented Sep 14, 2020 at 18:20
  • 1
    \$\begingroup\$ (suggestion), If the special thing is a type-level, then have a empty interface, let say SpecialType, and simply implement it by those special types, later check as if(obj instanceOf SpecialType). Not sure what's this feign, but it comes with a good API, it would provide some creation API to allow you customize(take-control) object instancing. \$\endgroup\$
    – user230399
    Commented Sep 14, 2020 at 19:04
  • \$\begingroup\$ You could manage the preloaded types in a Set<String> because you need uniqueness for the strings. \$\endgroup\$ Commented Sep 14, 2020 at 19:40
  • \$\begingroup\$ @911992 & @Mark Bluemel - Feign actually delegates to Jackson for deserialization.I didn't realize this until I did some research. So, it's actually Jackson that is creating the instances of Type. Jackson does support deserialization into subclasses. So, subclassing is an option. \$\endgroup\$ Commented Sep 15, 2020 at 14:22

1 Answer 1

2
\$\begingroup\$

First of all, as "being special" is obviously an attribute of your Type class, the check should go into the Type class, as you did, therefore always choose:

public class Type {
    ...
    public boolean isSpecial() {...}
}

over

aType.equals(new Type("specialType1")) || aType.equals(new Type("specialType2")) ||...

Regarding the implementation: I'm not too fond of creating a static collection to compare to. First of all, you search every time, then you use a relatively heavyweight equals method, which seems somewhat exaggerated to me, if the only distinction is a string passed in the constructor.

Personally, I'd use the underlying strings as a constant and determint the special flag in the constructor:

public class Type {
    private static final List<String> SPECIAL_CODES = Arrays.asList("this", "that", "whatever");
    private final String code;
    private final boolean special;

    public Type(String code) {
        this.code = code;
        this.special = SPECIAL_CODES.contains(code);
    }

    public boolean isSpecial() {
        return special;
    }
}

(Note that this change will not make a difference in runtime in real life, unless you check isSpecial() in a tight loop. It is more of a gut-feeling of being somewhat clearer.)

\$\endgroup\$
3
  • \$\begingroup\$ Thank you for your insights. This is very helpful. How would you compare this solution to having SpecialType extends Type? \$\endgroup\$ Commented Sep 15, 2020 at 14:29
  • 1
    \$\begingroup\$ I'd only go for inheritance, if you have a real extension of functionality, but never as a pure marker. \$\endgroup\$
    – mtj
    Commented Sep 15, 2020 at 16:25
  • \$\begingroup\$ Thanks. Yeah, the special types have no additional functionality (i.e. no extension of behavior, no additional fields). So it would be purely as a marker. \$\endgroup\$ Commented Sep 15, 2020 at 18:00

Not the answer you're looking for? Browse other questions tagged or ask your own question.