2

I know there are several similar topics with similar title but I have actually slightly different questions than other topics.

I have designed such a solution which abstract class implements and interface, and in the constructor it calls default method of interface to initialize a map.

Here is my interface:

   public interface ICalculator{

        int VALUE_OF_X= 10;
        int VALUE_OF_Y= 50;
        int VALUE_OF_Z = 70;


        Map<String, Integer> CHAR_VAL_MAP = new HashMap<String, Integer>(7);

        default void initValueMap(){
            CHAR_VAL_MAP.put("X", VALUE_OF_X);
            CHAR_VAL_MAP.put("Y", VALUE_OF_Y);
            CHAR_VAL_MAP.put("Z", VALUE_OF_Z);
        }

        public int calculate(final String inStr);
}

And created an abstract class:

 public abstract  class AbstractCalculator implements ICalculator{

    protected AbstractCalculator(){

        initValueMap();
    }
}

My idea was here to ensure that initValueMap method is called implicitly by the abstract class.

And the concreate class which extend abstract class is:

public class MyCalculator extends AbstractCalculator{

    public int calculate(final String romanNumberStr){
        // some logic code
    }
}

I have basically two question:

1) Is there any design problem or wrong usage of OOP concepts ? 2) In C++. using const for the parameter is good programming behaviour. But in java word, it is not so common. Is it bad to use final in method parameters?

user1474111
  • 1,356
  • 3
  • 23
  • 47
  • "Is it bad to use final in method parameters?" - It doesn't mean what you expect it to mean, I suspect. It just means the value of the parameter itself isn't changed within the method, which is irrelevant for callers to know. It doesn't stop the object that the parameter's value refers to from being mutated - not an issue for `String`, but if you pass in a `List` for a `final List` parameter, the code can still add or remove elements, for example. – Jon Skeet Mar 16 '19 at 13:01
  • So basically you want to pre-initialize the map with the values in question – akortex Mar 16 '19 at 13:04
  • I want to just initialize the map before calling the calculate method, without explicit calling in concreate class. – user1474111 Mar 16 '19 at 13:05
  • What Java version are you using? – akortex Mar 16 '19 at 13:07
  • i use java 8 here – user1474111 Mar 16 '19 at 13:30
  • Regarding your comment: sure, that is a valid pattern. Like list interface and the abstractlist base class in the collection framework. – GhostCat Mar 16 '19 at 14:58

2 Answers2

3

You are over complicating things. Java 9 added some nice of() methods to the Collections utility class. You can use those to create a map filled with values without the need to call an extra init method. Then you pass that map instance to new HashMap() to get that data into a modifiable map instance. And with older java, you can always write a method that creates and returns a prefilled map. There is no need to do creation and filling like you do (in separate pieces of code).

For the record: you understand that all fields of an interface are static by default and thus shared between all code using them?!

Regarding final, there are quite some differences to const from C++. The only thing that a final parameter gives you is checking that prevents you from inadvertently writing to a parameter. It can be useful to have that, but most people simply don't use it because they add such little gain, but make code quite harder to read.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Thank you. Actually I am using java 8 but it is good know how it can be done in java 9. – user1474111 Mar 16 '19 at 13:37
  • One more thing is, that the person who I was discussed this solution, did not understand why I used both interface and abstract class. As I know there are some classes designed similarly in jdk. Isn't it common practice to use both abstract class and interface? – user1474111 Mar 16 '19 at 13:41
0

There are a few ways to ensure that calculate is only called after the map is fully initialized. One way is to declare and initialize it in the interface directly:

public interface ICalculator {

    int VALUE_OF_X = 10;
    int VALUE_OF_Y = 50;
    int VALUE_OF_Z = 70;

    Map<String, Integer> CHAR_VAL_MAP = initValueMap();

    static Map<String, Integer> initValueMap() {

        Map<String, Integer> map = new HashMap<String, Integer>(7);
        map.put("X", VALUE_OF_X);
        map.put("Y", VALUE_OF_Y);
        map.put("Z", VALUE_OF_Z);

        return map;
    }

    public int calculate(final String inStr);
}

This may be preferred because static data is being initialized statically, where it is declared (though most of us don't particularly like stuffing interfaces with this kind of code).

If you want to call this initialization code in the abstract class, you can still use a static block:

public abstract class AbstractCalculator implements ICalculator {
    static {
        ICalculator.initValueMap();
    }
}

But the simplest is perhaps to go with Map.of as suggested in GhostCat's answer, unless your Java runtime is older than 9.

ernest_k
  • 44,416
  • 5
  • 53
  • 99