Is there a way to make sure classes implementing an Interface implement static methods?

后端 未结 9 1942
礼貌的吻别
礼貌的吻别 2021-01-07 17:11

First of all, I read erickson\'s useful reply to \"Why can’t I define a static method in a Java interface?\". This question is not about the \"why\" but about the \"how then

相关标签:
9条回答
  • 2021-01-07 17:46

    Your answer to your own question can be simplified further. Keep the ParametricFunction interface as-is, and change Parabola into a singleton that implements ParametricFunction:

    public class Parabola implements ParametricFunction {
      private static Parabola instance = new Parabola();
    
      private Parabola() {}
    
      static public ParametricFunction getInstance() {
        return instance;
      }
    
      public double getValue(double x, double[] parameters) {
        return ( parameters[2] + x*(parameters[1] + x*parameters[0]));
      }
      public String getName() { return "Parabola"; }
      public boolean checkParameters(double[] parameters) {
        return (parameters.length==3);
      }
    }
    

    Indeed, if there is no particular reason why Parabola needs to be a singleton class, you could get rid of the static method and attribute and make the constructor public.

    The purpose of creating an instance of Parabola is to simplify your application.

    EDIT in response to your question below:

    You cannot use standard Java constructs to force a class to implement a static method with a given signature. There is no such thing as an abstract static method in Java.

    You could check that a static method is implemented by writing a separate tool that runs as part of your build and checks either the source code or the compiled code. But IMO, it is not worth the effort. Any missing getInstance() will show up if you compile code that calls it, or at runtime if you try to use it reflectively. That should be good enough, in my opinion.

    Besides, I cannot think of a convincing reason why you need the class to be a singleton; i.e. why the getInstance method is necessary.

    0 讨论(0)
  • 2021-01-07 17:50

    The reason is readability: fit("Parabola", xValues, fValues) vs. fit(Parabola.getInstance(), xValues, fValues) vs. fit(new Parabola(), xValues, fValues). Why would I want to have an Instance of function defined entirely by it's arguments with no internal data?

    Actually you are missing something about oriented object programming basics...

    If you define an object Parabola, this object should represent a Parabola, and not a toolbox to check parameters are ok etc...

    Your Parabola item should contain the parameters (x, y ...) and you could pass them with constructor...

    double x;
    double [] parameters;
    public Parabola(double x, double[] parameters) {
      this.x = x;
      this.parameters = parameters;
    }
    

    Thus you shouldn't use parameters on your function since the parameters are now declared as class member attributes...

    public double getValue() {
      return ( this.parameters[2] + x*(this.parameters[1] + x*this.parameters[0]));
    }
    

    Then just call

    parabolaInstance.getValue();
    
    0 讨论(0)
  • 2021-01-07 17:51

    @Sebastien: Why is there no interest for both classes to share the exact same static method name? Using reflection this might be the only way to make sure the method exists. I would like getDescription() to return the description of the class. Why should it change on different instances? That's why I'd like this method to be static and yet enforce in an Interface-like way that it is implemented. – Tobias Kienzler 3

    As i already said declaring the method static means you can call it directly from the class and don't need a class instance. Since it has no sense to call I.staticMethod() (as already explained), you just can call A.staticMethod1() and B.staticMethod2(), their name doesn't matter at all since you call them from the A or B class, known at compile time!

    If you want a getDescription to return the same description no matter the instance of ParametricFunction concerned, just make the ParametricFunction an abstract class and implement the static methods directly in this class. Then you'll be able to call A, I or B.getDescription(); (even a,i or b...). But it remains the same than implementing it in A and B and calling it threw A or B...

    Calling a static method from an instance is not a good practice and has no interest, so you should call A.meth(), or B.meth() and not a.meth() or b.meth()

    Because I wanted A and B to implement that staticMethod for sure and make sure someone else using the Interface for a new class will do so, too. – Tobias Kienzler 5 hours ago

    Actually "someone else" will normaly not call a.meth() or b.meth() thus if he makes a class C and want to call the C.meth() he'll never be able to do that because C.meth() is not implemented or not static... so he will do it, or the C.meth() would never been called and then it is also non sense to force developpers to implement static functions that would never be used...

    I don't know what i can add...

    0 讨论(0)
  • 2021-01-07 17:54

    The idea behind this is putting several ParametricFunction's in a package and use Reflection to list them all, allowing the user to pick e.g. which one to plot.

    That's going to fail for a more basic reason: reflection offers no way to list all classes in a package (because "all classes in a package" is not a well-defined set, due to the flexibility of the classloader mechanism).

    The modern solution for this kind of thing is to make it part of the application configuration via a dependency injection framework.

    Obviously one could provide a loader class containing an array of the available ParametricFunction's, but every time a new one is implemented one has to remember adding it there, too.

    Well, with your concept, every time a new one is implemented, one is forced to put it into the same package. By putting it into a configuration file or a loader class (the same thing, really), you remove that restriction.

    0 讨论(0)
  • 2021-01-07 17:54

    Constructor in interface? uh? Would you like to be able to call Interface i = new Interface(double[] parameters)? And the computer would another time choose himself the implementation? This is as much strange as static in interface :D

    As you said, checking parameters should be done before construction... But this doesn't mean you can't raise exception on construction if parameters are not ok. It's just a security you can add, that will ensure that the constructed object will be coherent. But such code doesn't allow you to bypass a previous validation: raising exception on construction will tell you "hey you have a bug!" while not validating the params will just tell you "hoho someone using GUI tried to set a bad value, we'll send him an error message..."

    Actually, since you need to validate the values, and the object is not even constructed, why do you absolutly want to add this validation on the model object? Form/Gui/whatever validation could be done anywhere, in a validation java class... Just set a static (or not) method, in another class called ParametricFunctionValidationHelper, where you add your method and the validation implementation.

    public static boolean validateParametricFunction(String functionType, double[] parameters) {
      if ( functionType.equals("bessel") ) return validateBessel(parameters);
      if ( functionType.equals("parabola") ) return validateParabola(parameters);
    }
    

    It doesn't matter how is represented your functionType (i choose String because i suppose you get it from user interface, web or gui... it could have been Enum...

    You can even validate the object after having constructed it:

    public static boolean validateParametricFunction(ParametricFunction pamFunc) {
      if ( pamFunc instanceOf BesselFunction ) return validateBessel(pamFunc.getParameters);
      ......
    }
    

    You can even put static validation methods in function classes and then you'll have: public static boolean validateParametricFunction(ParametricFunction pamFunc) { if ( pamFunc instanceOf BesselFunction ) return BesselFunction.validateBessel(pamFunc.getParameters); if ( pamFunc instanceOf ParabolaFunction ) return ParabolaFunction.validateParabola(pamFunc.getParameters); }

    Yes you won't be able to set the static method in the interface but anyway how would you call such a method?

    With code like

    public static boolean validateParametricFunction(ParametricFunction pamFunc) {
      return ParametricFunction.validate(pamFunc);
    }
    

    ??? This as no sense because the JVM won't be able at all to know which implementation of the static method to use since you don't call the static method from an instance but from a class! It as only sense if you implement the validate method directly in the ParametricFunction class, but anyway if you do such a thing you'll have to do exactly the same that i've shown you before with the instanceOf, because the instance of the pamFunc is the only item you'll have to select which kind of validation you'll have to use...

    That's why you'd better use a non static method and put it in the interface like:

    public static boolean validateParametricFunction(ParametricFunction pamFunc) {
      return pamFunc.validate();
    }
    

    Actually what you should do is: - Retrieve parameters (String?) from GUI / Web interface / anything - Parse String parameters in good format (String to int...) - Validate these parameters with a validation class (static method or not) - If no validation -> print message to user - Else construct object - Use the object

    I don't see anywhere a need of static method in interface...

    0 讨论(0)
  • 2021-01-07 17:56

    What you want to do is not ok...

    You want to define static methods in an interface I and have some implementations A and B of this interface, with their own implementation of these static methods declared in the interface I.

    Just imagine, how the computer would know what to do if you call I.staticMethod() ??? will it use the implementation of A or B?!!

    The interest to declare a method in the interface is to use polymorphism and be able to call this method for different object implementations... But for static methods, since you don't call the method from an instance (actually you can but not really needed...) but with ClassName.xxxMethod, it absolutly has no interest...

    Thus you don't have to put these static methods in the interface... just put them in the both implementations and call them with A.staticMethod() and B.staticMethod() (and they don't even need to share a same method name!)

    I wonder how you want to call your static method, do you sample code to show?

    0 讨论(0)
提交回复
热议问题