Java: передать параметр в конструктор или метод? - PullRequest
3 голосов
/ 19 июля 2011

В настоящее время у меня есть класс, TransactionData, который немного больше, чем POJO. Я строю объект из HTTPServletRequest. Что я делаю:

public class TransactionData
{

    // ...

    public TransactionData(HttpServletRequest request) throws IOException
    {
        // do actual work here
    }

}

Здесь много WTF, наиболее тревожным является то, что объект TransactionData тесно связан с HTTPServletRequest. Что я подумал: создать интерфейс TransactionDataExtractor с методом extract(), чтобы я мог реализовать разные классы для создания объекта.

public interface TransactionDataExtractor
{
    public TransactionData extract();
}

Но как передать материал, необходимый для построения TransactionData, каждой реализации? Первое, что пришло в голову, - это использовать различные конструкторы, например:

public class TransactionDataExtractorRequest implements TransactionDataExtractor
{
    private HttpServletRequest httpRequest;

    public TransactionDataExtractorRequest(HttpServletRequest httpRequest)
    {
        this.httpRequest = httpRequest;
    }

    public TransactionData extract()
    {
        // do whatever is required
    }

}    

Но в этом случае всякий раз, когда мне нужно создать новый объект TransactionData, я должен создать новый TransactionDataExtractorRequest. Неявная зависимость мне совсем не нравится. Другой альтернативой, о которой я мог подумать, была передача параметра Object в extract() и приведение его при необходимости, отказ от безопасности типов и введение большого количества уродливого кода котельной пластины

    public TransactionData extract(Object o)
    {
        HttpServletRequest h;
        if (o instanceof HttpServletRequest)
        {
             h = (HttpServletRequest)o;
        } 
        //...
    }

Я не знаю, ясно ли я объяснил. Я чувствую, что что-то упустил, я знаю, что решение очень простое, но я не могу его достать. Какие-нибудь мысли? ТИА.

РЕДАКТИРОВАТЬ: проблема может даже заключаться в том, что моя догадка совершенно неверна, и я могу отклонить ее без сожаления

Ответы [ 5 ]

4 голосов
/ 19 июля 2011

Если ваша единственная проблема заключается в обеспечении безопасности типов при передаче исходного объекта в extract(), вы можете использовать обобщенные значения:

public interface TransactionDataExtractor<E> {
    public TransactionData extract(E source); 
} 

public class TransactionDataExtractorRequest 
    implements TransactionDataExtractor<HttpServletRequest> {
    public TransactionData extract(HttpServletRequest source) { ... }
} 
3 голосов
/ 19 июля 2011

Если вы полагаетесь только на параметры запроса, вы можете получить request.getParameterMap() и использовать вместо него Map.(если вам нужны заголовки - getHeaders())

3 голосов
/ 19 июля 2011

Я чувствую, что что-то упустил ... Есть мысли?

Ну, я думаю, вы пытаетесь решить проблему, которая на самом деле не является проблемой.Нет никакой очевидной (для меня) причины, почему муфта, от которой вы пытаетесь избавиться, действительно вредна.Конечно, ваши попытки удалить связь не облегчают понимание кода.

1 голос
/ 19 июля 2011

Я до сих пор не убежден, что многое удаляется, удалив зависимость от HttpServletRequest, но я бы предложил что-то вроде:

public class TransactionData {
    public TransactionData(TransactionDataOptions options) throws IOException {
        // do actual work here
    }
}

//TransactionData wants some state that it currently gets from a HttpServletRequest,
//figure out what that state is, and abstract an interface for accessing it
public interface TransactionDataOptions {
    //getters for things that TransactionData needs
}

//take all the code that pulls state out of the HttpServletRequest, and move it here
public class TransactionDataHttpOptions implements TransactionDataOptions {
    private HttpServletRequest request;

    //getter implementations that pull the required information out of the request

    public TransactionDataHttpOptions(HttpServletRequest request) {
        this.request = request;
    }
}

//now you can also do this, and use TransactionData even without a HttpServletRequest
public class TransactionDataMapOptions implements TransactionDataOptions {
    private Map<String, Object> map;

    //getter implementations that pull the required information out of the map

    public TransactionDataHttpOptions(Map<String, Object> map) {
        this.map = map;
    }
}

Если вы пойдете по этому пути, то TransactionDataHttpOptions является единственным объектом с зависимостью от HttpServletRequest.И так как это в основном оболочка, которая предназначена для работы с HttpServletRequest, я думаю, что все будет в порядке.

1 голос
/ 19 июля 2011

Создание / повторное использование экземпляра TransactionDataExtractorRequest не проблема, ИМХО.В любом случае вам нужно где-то различать типы параметров, и если вы отделите TransactionData от типов параметров с помощью какой-то фабрики, что с этим не так?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...