Вытягивание зависимостей из "божьих" объектов в DI-фреймворке - PullRequest
5 голосов
/ 16 августа 2011

У меня есть сервлет с большим количеством существующего кода. Я пытаюсь добавить внедрение зависимости в одну часть. В настоящее время я делаю это вручную:

public class AdjustBookPriceHandler extends BookRequestHandler {
    @Override
    public void handleRequest(RequestState requestState, RequestData requestData, Object obj) {
        Book book = (Book) obj;
        long newPrice = Long.parseLong(requestData.getQueryParam("price");
        OfferRepository offerRepository = ((BookData) requestState.getData()).getOfferRepository();

        BookPriceAdjuster priceAdjuster = getBookPriceAdjuster();
        priceAdjuster.adjustPrice(newPrice);
    }

    protected BookPriceAdjuster getBookPriceAdjuster(RequestState requestState, RequestData requestData, Book book) {
        return new BookPriceAdjuster(book, offerRepository);
    }
}

Здесь зависимости от книги и предложения вводятся в BookPriceAdjuster через конструктор. Метод getBookPriceAdjuster позволяет классам, которые наследуются от AdjustBookPriceHandler, предоставлять другой регулятор цены.

Я хотел бы начать использовать DI-фреймворк, такой как Guice, для сокращения некоторого стандартного кода, который будут представлены в сложных примерах. Тем не менее, я не уверен, как лучше использовать его в этом контексте.

Как я могу написать привязки, которые бы вытягивали соответствующие зависимости из "божественных" объектов RequestState и RequestData? Или на этом этапе использование фреймворка будет таким же сложным и грязным?

Ответы [ 2 ]

0 голосов
/ 19 октября 2012

Как мне написать привязки, которые бы вытягивали соответствующие зависимости из "божественных" объектов RequestState и RequestData?

Здесь вы можете довольно легко начать использовать Guice для внедрения зависимостей, в зависимости от того, как загружается ваше приложение. Допустим, у вас есть Книжный модуль.

public class BooksModule extends AbstractModule {
    protected void configure() {
        // Do Nothing
    }

    @Provides @RequestScoped
    BookData provideBookData(RequestState requestState) {
      return (BookData) requestState.getData();
    }

    @Provides @RequestScoped
    OfferRepository provideOfferRepository(BookData bookData) {
      return bookData.getOfferRepository();
    }
}

Теперь вы можете использовать Guice для внедрения зависимостей в ваш класс BookPriceAdjuster.

@RequestScoped
public class BookPriceAdjuster {
    private final Book book;
    private final OfferRepository offerRepository;

    @Injected
    public BookPriceAdjuster(Book book, OfferRepository offerRepository) {
        this.book = book;
        this.offerRepository = offerRepository;
    }

    // whatever methods it has
}

И теперь вы можете использовать провайдера для вашего BookPriceAdjuster внутри вашего сервлета.

public class AdjustBookPriceHandler extends BookRequestHandler {

    private final Provider<BookPriceAdjuster> bookPriceAdjusterProvider;

    @Injected
    public AdjustBookPriceHandler(Provider<BookPriceAdjuster> bookPriceAdjusterProvider) {
        this.bookPriceAdjusterProvider = bookPriceAdjusterProvider;
    }

    @Override
    public void handleRequest(RequestState requestState, RequestData requestData, Object obj) {
        Book book = (Book) obj;
        long newPrice = Long.parseLong(requestData.getQueryParam("price");

        BookPriceAdjuster priceAdjuster = bookPriceAdjusterProvider.get();
        priceAdjuster.adjustPrice(newPrice);
    }
}

Чтобы загрузить приложение, вам нужно установить BooksModule с помощью инжектора Guice. Как вы поступите с этим, зависит от того, как ваше приложение загружается в данный момент. Для сервлетов я настоятельно рекомендую изучить расширение Guice-Servlet , которое позволяет вам определять ваши сервлеты и зависимости в «типобезопасной идиоматической Java» вместо файла web.xml. Красиво просто.

Или на этом этапе использование фреймворка было бы таким же сложным и грязным?

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

0 голосов
/ 14 сентября 2011

Я не уверен, правильно ли я понимаю, что вы пытаетесь сделать.Книга находится в области запроса, а предложение Repository - в одной области?Если это так, вы можете сделать что-то вроде этого ..

public class AdjustBookPriceHandler extends BookRequestHandler {

    // inject concrete instance with setter or constructor
    private BookPriceAdjusterProvider bookPriceAdjusterProvider;

    @Override
    public void handleRequest(RequestState requestState, RequestData requestData, Object obj) {
        Book book = (Book) obj;
        long newPrice = Long.parseLong(requestData.getQueryParam("price");

        BookPriceAdjuster priceAdjuster = bookPriceAdjusterProvider.getBookPriceAdjuster(book);
        priceAdjuster.adjustPrice(newPrice);
    }

}

public interface BookPriceAdjusterProvider {

    BookPriceAdjuster getBookPriceAdjuster(Book book);

}

public class MyBookPriceAdjusterProvider {

    // inject this through setter or constructor
    private OfferRepository offerRepository;

    protected BookPriceAdjuster getBookPriceAdjuster(Book book) {
        return new BookPriceAdjuster(book, offerRepository);
    }
}

Таким образом, вы избавитесь от синглтоновой области действия OfferRepository и сможете использовать некоторую инфраструктуру DI, чтобы выполнить внедрение для вас.Вы также можете использовать различные реализации BookPriceAdjusterProvider, если это необходимо в ваших подклассах или около того.Это то, что вы хотели, или я неправильно понял вашу цель?

...