Java-интерфейсы, шаблоны создателей и метод getInstance () или эквивалентный - PullRequest
5 голосов
/ 25 июля 2011

Я хотел бы начать с упоминания, что моя проблема проистекает из того факта, что интерфейсы в Java не допускают статические методы.Там были дискуссии о причине этого на SO ( здесь , например).Поэтому не будем останавливаться на этом.Я ищу способ для своего интерфейса создать экземпляр себя (точнее, его реализацию) и вернуть его.Несмотря на то, что я играю с паттернами Singleton, Factory и AbstractFactory, я все еще не могу достичь своей цели.

Чтобы уточнить то, что я пытаюсь - вот мой интерфейс:

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);
}

ИВот мой уровень бизнес-логики:

public class BusinessLogicLayer {

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

}

Я пытался использовать шаблон фабрики следующим образом:

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.
         */
    }
}

Однако для этого все еще требуется, чтобы уровень Business Logic знал класс реализации NoteDataStoreFactoryImpl таким образом:

NoteDataStore = new NoteDataStoreFactoryImpl().getDataStoreInstance();

Как мне обойти это?Как сохранить свой BusinessLogicLayer в неведении относительно точного используемого класса реализации?


РЕДАКТИРОВАТЬ: более подробно Предпосылки моей проблемы

В нескольких ответах предлагается использование каркасовкак веснаУвы, я не могу этого сделать, потому что это приложение предназначено для различных мобильных платформ (Android, Blackberry, JavaME).Я должен был это прояснить в своем первоначальном вопросе - извиняюсь за то, что не сделал этого.

Мое главное намерение - иметь приложение на разных платформах.Пользовательский интерфейс, доступ к базе данных, транспортные уровни HTTP и т. Д. Должны быть закодированы специально для каждой платформы.Однако бизнес-логика достаточно проста, чтобы гарантировать общий уровень для всех платформ.Я намерен распространять слой бизнес-логики в виде библиотеки JAR.Кроме того, слой синтаксического анализа и формирования кадров (для JSON / XML).

В SO уже обсуждался этот вопрос (о том, должен ли я даже идти по этому пути) - Повторное использование логического кода.Тем не менее, при условии, что это нормально, и что я продолжаю с многоуровневым подходом и намерением иметь один общий уровень в коде.Теперь моя ситуация такова:

  1. Общий уровень бизнес-логики.
  2. Уровень данных для платформы (представлен интерфейсом NoteDataStore)
  3. Уровень ядра приложения для конкретной платформы (Контроллер, если можно так назвать).

Обратите внимание, что, если я использую шаблон Фабрики или другой, я могу позволить себе иметь этот слой, специфичный для каждой платформы.,Таким образом, сам метод / класс фабрики может знать о классе реализации NoteDataStore.Однако уровень бизнес-логики не должен знать ни о каком из классов реализации.

Типичное использование различных уровней будет следующим:

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();
    }
}

Любые входные данные о том, как обрабатывать этосценарий

Ответы [ 5 ]

5 голосов
/ 25 июля 2011

Ваш класс должен принимать фабричный экземпляр извне. Когда вы создаете экземпляр самостоятельно - вы ничего не добиваетесь, вы здесь правы.

Здесь есть несколько техник. В общем, они относятся к чему-то очень общему, называемому Inversion of Control или сокращенно IoC Также полезно знать об «Инверсии Контейнеров Контроля» или IoCC. Например, в Java есть Spring - читайте здесь . Вы должны спросить настоящих парней из Java о других:)

Также взгляните на эту статью .

2 голосов
/ 25 июля 2011

Если вы хотите вернуть реализацию, вы можете сделать это с помощью анонимного внутреннего класса

NoteDataStore myImplementation = new NoteDataStore (){
//Implement methods here
};
0 голосов
/ 17 января 2017

Предлагаем вам использовать ID-фреймворки, такие как Guice и другие.Не просто использовать Factory Pattern.

0 голосов
/ 27 июля 2011

Я, наконец, обратился к предложению @Ray Tayek в комментарии к первоначальному вопросу.Я просто передаю экземпляр NoteDataStore во время создания BusinessLogicLayer.

Это простое решение вполне соответствует моим потребностям, так как мне не нужна фабрика.Моей главной целью было, чтобы уровень BL не знал точных классов реализации используемых им интерфейсов.Теперь вместо Фабрики именно базовый уровень «Контроллер» создает конкретную реализацию интерфейсов и передает их на уровень BL.Это просто идеально!

Вот фрагмент кода.

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
    }

}
0 голосов
/ 25 июля 2011

Вы смотрели на интегрированные среды IoC / Dependency Injection, такие как Guice и Spring? Они могут быть слишком тяжелыми для того, что вы ищете, но они определенно решают проблему, которую вы описываете. Они позволяют писать весь код вашего бизнес-уровня для интерфейсов, а фактические реализации можно определять с помощью инфраструктуры IoC. Я лично большой поклонник Spring и использовал его почти во всех Java-приложениях, которые я написал за последние 6 с лишним лет.

...