-1

I have a class named ManagementServiceHandler that implements an interface. In this class, there are a few variables and methods, and among them there is a private static map and two static methods:

public class ManagementServiceHandler implements ManagementService.Iface {

  private static Map<NodeManifest, Integer> nodePorts;

  ... other methods and variables
  ...
  ...   

  public static Map<NodeManifest, Integer> getNodePorts() {
        return nodePorts;
  }


  public static void setNodePorts(Map<NodeManifest, Integer> nodePorts) {
    ManagementServiceHandler.nodePorts = nodePorts;
  } 

The Object NodeManifest is something like:

class NodeManifest {
String hostName;
List<String> servicelist;
}

Other methods handle registration and de-registration of objects NodeManifest into the Map nodePorts, and requests from a NodeManifest of a particular service present in the Map. If a service requested is present, then is is used by the NodeManifest that asked for it.

I have a junit test file containing this:

public class ManagementServiceTest {

 public static class ManagementServer implements Runnable {
    code for ManagementServer
 }

 ...
 ...

public static class ArithmeticServer implements Runnable {
    code for ArithmeticServer
}

...
...


  public void testArithmeticServerCompletion() throws Exception {

    class ArithmeticServiceDispatcher {

        public long executeOperation(String opName, int num1, int num2) throws TException {
            long result = 0;
            for(Map.Entry<NodeManifest, Integer> pair : ManagementServiceHandler.getNodePorts().entrySet()) {
                List<String> operations = pair.getKey().serviceList;
                if(operations.contains(opName)) {
                    switch(opName) {
                    case "addition":
                        result = arithmeticClient.add(num1,  num2);
                        break;
                    case "multiplication":
                        result = arithmeticClient.multiply(num1,  num2);
                        break;
                    case "substraction":
                        result = arithmeticClient.substract(num1,  num2);
                        break;
                    case "division":
                        result = arithmeticClient.divide(num1,  num2);
                        break;
                    }
                break;
                }
            }
        return result;
        }
    }

My problem is that right now, either the Map contained in the class ManagementServiceHandler and the two methods getNodePorts() and setNodePorts() must be static if I want the method executeOperation in the test file to access the correct Map containing the NodeManifests registered.

I was told that it's not correct, in this case, to use static methods and variables; however, if I make those non-static, then I need to change something in executeOperations() in order for it to access the correct Map nodePorts that contains all the NodePorts registered. I cannot use

ManagementServiceHandler.getNodePorts() 

but I still need to access data in the Map nodePorts filled with NodeManifest objects in order to make executeOperation() work as intended.

So my questions are two:

  1. why i cannot use static in this case?
  2. how to modify executeOperation() in order for it to access the Map nodePorts created by ManagementServiceHandler when it's not empty?
Gaspare79
  • 51
  • 1
  • 9
  • Have you tried to ask these questions to the person that told you "it's not correct, in this case, to use static methods and variables"? – Pino Jun 09 '14 at 08:24
  • I would have, but he is away and unreachable for a few days and I need to know this as soon as possible. – Gaspare79 Jun 09 '14 at 08:27
  • Maybe [this](http://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class) will help answering you with the static issue. – Sky Jun 09 '14 at 08:27
  • mmh thanks for the link but it doesn't help me much, it is about static and nested class, but I have a static method inside a class, and a class that must access data from another class... I'm confused... – Gaspare79 Jun 09 '14 at 08:48
  • ok, I got that I need to instantiate an object of the type ManagementServiceHandler in order to access it methods, but I need to access the Map nodePorts also. – Gaspare79 Jun 09 '14 at 09:16
  • Is it acceptable for your application to handle exactly ONE nodePorts map? Do you know what a singleton is? Will your application run in a cluster? It seems that you have decided to use static method and variable just because it's easier to write a unit test but this is not a good reason for any design decision. – Pino Jun 09 '14 at 09:21
  • I didn't decide to use static method and variables, it has been eclipse that "suggested" me to use that. Then I discovered that it isn't a correct way to code, and now I'm trying to fix it. I haven't decided anything. To answer your questions, it is acceptable because I will work with only one ManagementService at a time, but now I also know that it is not a good implementation if one day I decide to work with more than one ManagementServiceHandler... – Gaspare79 Jun 09 '14 at 09:30
  • Sorry for the series of posts, but I'd like to make it clear that i'm still learning java coding, so I'm sorry if I don't know exactly how to explain my problems or I ask things badly... So please don't be aggressive at me, there is no reason.. – Gaspare79 Jun 09 '14 at 09:38
  • It sounds like you might not *completely* understand the difference between `static` and non-`static` yet (don't feel bad if that's the case, lots of people don't at first, myself included). I posted [an explanation of the difference between the two](http://stackoverflow.com/questions/23860661/cannot-make-a-static-reference-to-the-non-static-method/23860891#23860891) that you might find it helpful to read. Hopefully it will help you to understand why you were told that `static` wasn't appropriate for this scenario. – JonK Jun 09 '14 at 09:53
  • Thank you for the link, I've read your answer and it was helpful to clarify the difference between static and non-static. However, not completely helpful because in my case, if I create an instance of ManagementServiceHandler into the class ArithmeticServiceDispatcher, then each time I call the method to get any operation, the map the method looks for to fetch the requested operation is the map of the ManagementServiceHandler I instantiated, not the map where NodeManifest objects are actually stored. So the map is empty and I get always 0 as result. Not sure if i explained my issue correctly.. – Gaspare79 Jun 09 '14 at 10:06
  • So, if I put the map nodePorts and the methods as static, and then I just call ManagementServiceHandler.getNodePorts() inside executeOperation(), it works flawlessy. However, this is good only if I work with exactly one ManagementServiceHandler, which is actually the case, but I need to fix the code to non-static version if I decide one day that i want to work with more than one ManagementServiceHandler. This is the real issue, if I'm not mistaken. – Gaspare79 Jun 09 '14 at 10:10
  • Usually `Service` classes are *singletons* (further reading: [Singleton Pattern](http://en.wikipedia.org/wiki/Singleton_pattern)) so the kind of problem that you're hitting isn't normally an issue. Certainly if your application is using a framework like Spring, they will be singletons by default. If not, you may need to manually enforce that behaviour (if you have a copy of *Effective Java Second Edition* by Joshua Bloch, check Item 3 for the recommended approach). – JonK Jun 09 '14 at 10:50
  • and being a singleton means that I don't need to have static variables and methods, correct? – Gaspare79 Jun 09 '14 at 12:18
  • Being a Singleton means that only **one** object of the class can exist at any given time. One (of many) *implications* of this is that you're guaranteed to always be looking at the correct variables because there should only be that one copy of them. So yes, you could in theory drop the `static` from the variables and methods if you implemented the singleton pattern on the service. – JonK Jun 09 '14 at 23:57

1 Answers1

0

you have two options here, either keep the getters and setters as static methods and in this case you can invoke them using ClassName.methodName()

                                   OR

don't make them static and in this case you need to make an instance of the class ManagementServiceHandler and call these methods using objectName.methodName()... this is not a coding decision, it is a design decision that you have to make based on the way you are going to use the class ManagementServiceHandler.

Research for singleton pattern, maybe it is the design pattern that suits you best in your case.

Am_I_Helpful
  • 18,735
  • 7
  • 49
  • 73
Nawar Khoury
  • 170
  • 2
  • 13