Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get an instance of a subclass of abstract class from a static method of another class?

I have the following class structure:

  • DataStore classes:

    • Parent class: PStore: public abstract class PStore ...
    • 2 child classes extending it: CStore1 and CStore2
    • Each of the child classes is a N-glton (sorry, not sure what Java term for that is) - it can have only N instances, numbered 1..NMax.
    • Each child class has the following methods for accessing that instance: CStore1.getInstance(Id) and CStore2.getInstance(Id)
  • Worker classes:

    • Parent class: public abstract class PWork...
    • 2 child classes extending it: CWork1 and CWork2
  • Current situation:

    • Class CWork1 implemented an inner class with the following code accessing the Store:

      protected class fListener implements ActionListener {
              public void actionPerformed(ActionEvent ae) {
                  CStore1.getInstance(Id).someMethod();
                  # NOTE: someMethod() is implemented in CStore2 as well
              }
          }
      
    • I need to implement the same fListener class in CWork2

    • Being a good little software developer, instead of simply copy/pasting fListener from CWork1 to CWork2 class and then changing CStore1 to CStore2 in its code, I decided like an idiot to migrate it to a parent class.


  • What I tried to do:

    • Create an abstract method in PStore called getStoreInstance(int Id): public abstract PStore getStoreInstance(int Id);

    • Implement that method in CStore1 as public PStore getStoreInstance(int Id) { return CStore1.getInstance(Id); }

      So far, so good. It compiled all 3 Store classes.

    • Copy the fListener code from PWork to CWork1 class

    • Obviously, the compiler complained that it does not know anything about CStore1 class and its method getStoreInstance()

    • Now, I decided to simply call the newly created getStoreInstance():

      Old code: CStore1.getInstance(Id).someMethod();

      New code: PStore.getStoreInstance(Id).someMethod();

  • Compiler complaint: "Cannot make a static reference to the non-static method getStoreInstance(Id) from the type PStore".

  • The only "fix" proposed by Eclipse was to make getStoreInstance() method static, but THAT didn't work either:

    • When I added a static modifier to the abstract classes's declaration of the method: public static abstract PStore getStoreInstance(int Id); - the compiler complained that "The abstract method getStoreInstance in type PStore can only set a visibility modifier, one of public or protected"

    • When I tried to make the method non-abstract: public static PStore getStoreInstance(int Id); it complained that the method needed a body (quite sensibly)

    • When I tried to add a body, it required me to return PStore object... BUT!!!! My abstract class PStore has no constructore, so there's no way I can return PStore object!!!


Am I approaching the problem correctly?

If not, how should I approach it?

If I am, then how can I resolve the original complaint about "Cannot make a static reference to the non-static method", in light of the fact that the abstract class isn't letting me make that method static?

like image 917
DVK Avatar asked Nov 01 '22 23:11

DVK


1 Answers

The way it looks to me, you have two class hierarchies that are isomorphic (if I'm using the right term) and there is a relationship between the corresponding classes:

      PStore                   PWork
      /     \                 /     \
     /       \               /       \
   CStore1  CStore2        CWork1   CWork2
      ^         ^              ^      ^  
      |         |              |      | 
      |---------+--------------|      |
                |                     |
                |---------------------|

But I don't think there's a built-in way to express this kind of relationship in Java. Somehow, you're going to have to do something that makes those relationships explicit. I.e. there will need to be something in CWork1 that refers to CStore1, and something in CWork2 that refers to CStore2, or else some kind of list or map that associates them.

There's probably a design pattern that addresses this structure, but I can't think of it right now. So off the top of my head, here are a couple possible solutions (neither of which uses reflection):

  1. Put the abstract getStoreInstance method you defined in PWork instead of PStore. In CWork1, override it with a method that calls CStore1.getInstance, and similarly in CWork2. Then the common fListener actionPerformed code would call getStoreInstance(Id).someMethod(), with no class name, which would work on the current PWork instance. You would still have some "duplicated" code (since you'd have to implement getStoreInstance in both CWork classes), but it would be kept to a minimum.

  2. Set up a map. This compiles (Java 8), but I haven't tested it:

    class PWork {
    
        private static Map<Class<? extends PWork>,IntFunction<PStore>> storeMap;
        static {
            storeMap = new HashMap<>();
            storeMap.put(CWork1.class, CStore1::getInstance);
            storeMap.put(CWork2.class, CStore2::getInstance);
        }
    
        protected PStore getStoreInstance(int Id) {
            return storeMap.get(getClass()).apply(Id);
        }
    
        protected class fListener implements ActionListener {
            public void actionPerformed(ActionEvent ae) {
               int Id = ???; // I'm assuming Id is computed from ae somehow??
               getStoreInstance(Id).someMethod();
           }
        }
    
     }
    

Now getStoreInstance looks in the map, using the current PWork object's class (CWork1 or CWork2) as a key, to figure out which getInstance static method to call.

like image 182
ajb Avatar answered Nov 09 '22 08:11

ajb