Java interfaces, the creator patterns and the “getInstance()” method or equivalent

限于喜欢 提交于 2019-12-23 10:29:13

问题


I would like to start off by mentioning that my problem stems from the fact that interfaces in Java do not allow static methods. There have been discussions about the reason for this on SO (here , for example). So lets not dwell on that. I am looking for a way for my interface to create an instance of itself (rather, its implementation) and return that. In spite of playing around with Singleton pattern, Factory and AbstractFactory patterns, I still cannot achieve my goal.

To elaborate on what I'm trying - here's my interface:

public interface NoteDataStore {
    public boolean deleteNote(long noteId);
    public boolean addNote(Note note);
    public List<Note> listNotes();
    public boolean editNote(long noteId, Note note);
    public List<Note> search(String searchString);
}

And here's my business logic layer:

public class BusinessLogicLayer {

    public BusinessLogicLayer(){
        /*
         * GOAL: To get an instance of NoteDataStore here,
         *  without being aware of the implementation class.
         */
    }

}

I tried to use a factory pattern like so:

public interface NoteDataStoreFactory {
    public NoteDataStore getDataStoreInstance();
}

public class NoteDataStoreFactoryImpl implements NoteDataStoreFactory{
    public NoteDataStore getDataStoreInstance(){
        return NoteDataStoreImpl.getInstance();
        /*
         * Here, NoteDataStoreImpl is an implementation of NoteDataStore.
         * This should be transparent to my business logic layer.
         */
    }
}

However, this still requires the Business Logic layer to know the implementation class NoteDataStoreFactoryImpl thus:

NoteDataStore = new NoteDataStoreFactoryImpl().getDataStoreInstance();

How do I get around this? How do I keep my BusinessLogicLayer in the dark regarding the exact implementation class to use?


EDIT: More Detailed Background of my problem

A few of the answers suggest the use of frameworks like Spring. Alas, I cannot do so because this application targets various mobile platforms (Android, Blackberry, JavaME). I should have made this clear in my original question - apologies for not doing so.

My main intention is to have an app across platforms. The UI, database access, HTTP transport layers etc will have to be coded specifically for each platform. However, the business logic is simple enough to warrant a common layer across all platforms. I intend to distribute the business logic layer as a JAR library. So also, the parsing and framing layer (for JSON/XML).

There has already been a discussion about this at SO (on whether I should even be going down this path) - Logic Code reuse. However, assuming this is OK and that I proceed with the layered approach and the intention to have one layer common in code. Now, my situation is such that I have:

  1. A common Business Logic Layer.
  2. Platform-specific data layer (represented by the NoteDataStore interface)
  3. Platform-specific Application core layer (Controller, if I may call it so).

Note that if I use the Factory pattern or other such, I can afford to have that layer specific to each platform. So, the factory method/class itself can know about the NoteDataStore implementation class. However, the Business Logic Layer must be unaware of any of the implementation classes.

A typical use of the various layers would be as follows:

public class NoteDataStoreAndroid implements NoteDataStore{

    public boolean deleteNote(long noteId){
        /*
         * Android-specific database code
         */
    }

    /* ... similarly, other methods */
}


public class AndroidCoreApp{

    public void doBusinessLogic(){
        BusinessLogicLayer businessLogic = new BusinessLogicLayer();
        businessLogic.startBusinessLogic();
    }
}

Any inputs on how to handle this scenario?


回答1:


Your class should accept factory instance from the outside. When you're creating instance yourself - you achieve nothing, you are correct here.

There are several techniques here. In general they belong to something very general called Inversion of Control or IoC for short. Also it is useful to know about 'Inversion of Control Containers' or IoCC. Java has Spring for example - read here. You should ask real Java guys about others :)

Also take a look at this article.




回答2:


If you want to return an implementation you could do so with an anonymous inner class

NoteDataStore myImplementation = new NoteDataStore (){
//Implement methods here
};



回答3:


Have you looked at IoC/Dependency Injection frameworks like Guice and Spring? They may be too heavyweight for what you are looking for, but they definitely solve the problem you describe. They allow all of your business layer code to be written against interfaces, and the actual implementations to be defined via the IoC framework. I'm personally a huge fan of Spring and have used it in nearly every Java app I've written in the past 6+ years.




回答4:


I finally went for the suggestion provided by @Ray Tayek in a comment to the original question. I simply pass in an instance of the NoteDataStore at the time of creating the BusinessLogicLayer.

This simple solution suits my needs pretty well since I do not really require a Factory. My main objective was for the BL Layer to be unaware of the exact implementation classes of the interfaces it uses. Now, instead of a Factory, it is the core "Controller" layer that creates a concrete implementation of the interfaces and supplies them to the BL Layer. This is just perfect!

Here is the code snippet.

public class NoteDataStoreAndroid implements NoteDataStore{

    public boolean deleteNote(long noteId){
        /*
         * Android-specific database code
         */
    }

    /* ... similarly, other methods */
}


public class AndroidCoreApp{

    public void doBusinessLogic(){
        BusinessLogicLayer businessLogic = new BusinessLogicLayer(new NoteDataStoreAndroid());
        businessLogic.startBusinessLogic();
    }
}

public class BusinessLogicLayer {

    private NoteDataStore mDataStore;
    public BusinessLogicLayer(NoteDataStore dataStore){
        this.mDataStore = dataStore;

        //Do something useful with mDataStore
    }

    public void startBusinessLogic(){
        //Do something useful with mDataStore
    }

}



回答5:


Suggest you use ID frameworks, like Guice and others. Not simply use Factory Pattern.



来源:https://stackoverflow.com/questions/6811782/java-interfaces-the-creator-patterns-and-the-getinstance-method-or-equivale

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