How can I initialize interdependent final references?

无人久伴 提交于 2020-01-15 07:08:34

问题


I have a class and a factory function that creates new anonymous class objects extending that class. However, the anonymous class objects all have a method in which there are references to other objects. In my full program, I need this to create and combine parsers, but I've stripped down the code here.

class Base{
    public Base run(){
        return null;
    }   
    static Base factory(final Base n){
        return new Base(){
            public Base run(){
                return n;
            }
        };
    }
}

public class CircularReferences{
    public static void main(String args[]){
        final Base a, b;
        a = Base.factory(b);
        b = Base.factory(a);
    }
}

I get CircularReferences.java:17; error: variable b might not have been initialized. That's true, it wasn't, but can't I set aside space for these variables and then initialize them using references to these spaces, which will be filled with the proper values before they are ever actually used? Can I perhaps use new separately from the constructor? How can I create these variables so they reference each other?


回答1:


The quick answer is that you can't do this. If you absolutely must do something like this, then use a private setter on the class and bind things together after they are constructed (i.e. use enforced immutability instead of final fields). Hopefully it's obvious that I don't think this is a good idea - I just wanted to provide a answer to your actual question before I answer the way that I really want to.

OK - now that is out of the way, here's the real response that is called for here:

Generally speaking, this sort of situation is a strong indicator that refactoring is needed to separate concerns. In other words, the Base class is probably trying to be responsible for too many things.

I realize that the example is contrived, but think about what functionality requires the circular dependency, then factor that functionality out into a separate class/object that then gets passed to both of the Base constructors.

In complex architectures, circular dependency chains can get pretty big, but strictly forcing final fields is great way to look for those types of refactoring opportunities.

If you have a concrete example, I'd be happy to help with some refactoring suggestions to break a dependency like this.


concrete example provided - here's my suggestion:

It seems like there is a concern of obtaining an appropriate ParseStrategy based on a token. A ParseStrategyProvider. So there would be a TopLevelParseStrategy that reads the next token, looks up the appropriate parse strategy, and executes it.

TopLevelParseStrategy would hold a final reference to the ParseStrategyProvider.

The ParseStrategyProvider would then need to have a registration method (i.e. registerStrategy(token, parseStrategy) ).

This isn't functionally much different from doing this with enforced immutability via a private setter (the registerStrategy method is for all intents and purposes the same as the private setter), but the design is much more extensible.

So you'd have:

public ParseStrategy createParser(){
  ParseStrategyProvider provider = ParseStrategyProvider.create();
  TopLevelParseStrategy topLevel = new TopLevelParseStrategy(provider);
  provider.registerStrategy("(", topLevel);

  // create and register all of your other parse strategies

  return topLevel;
}


来源:https://stackoverflow.com/questions/32918373/how-can-i-initialize-interdependent-final-references

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!