Есть ли шаблон дизайна для этого случая пары классов? - PullRequest
3 голосов
/ 09 июля 2019

Эта проблема часто встречается в моих проектах. Предположим, что в качестве примера у меня есть два интерфейса, один для получения информации из API и другой для анализа этой информации.

public interface APIClient {...}

public interface APIParser {...}

Теперь, возможно, мне понадобятся разные API, поэтому у меня будет много реализаций для APICLient, но для каждой из этих реализаций потребуется свой APIParser.

Это приведет к этому типу структуры

public class APIClientA implements APIClient {...}
public class APIParserA implements APIParser {...}

public class APIClientB implements APIClient {...}
public class APIParserB implements APIParser {...}

...
...

Итак, в общем, это будет означать, что каждый раз, когда я хочу добавить новый тип API, мне придется создавать несколько классов для одного и того же типа и убедиться, что они взаимодействуют только друг с другом, а не с реализация других типов API.

Это выглядит очень похоже на то, что предлагает шаблон проектирования моста, но этот шаблон позволит любому APIClient использовать любой APIParser (я прав?)

Итак, есть ли лучшее решение? Или, может быть, это нормально, и нет необходимости в его рефакторинге.

Также, возможно, parse - не то слово, извините, но я хотел сказать, что я проанализировал ответ JSON / XML, чтобы получить из него конкретную информацию. То, как я анализирую каждый ответ, зависит от структуры, предоставляемой каждым API, поэтому мне понадобятся разные «парсеры»

EDIT:

Я немного расширю эту идею. Существует класс клиента, который использует APIClient для выполнения запроса с заданным типом параметров. Как только запрос удовлетворен ответом JSON, клиент использует соответствующий APIParser для получения конкретной информации об ответе.

public class ClientClass {

  ...
  json = APIClientTypeA.makeRequest(city, day, ...);
  temperature = APIParserTypeA.getTemperature(json);
  ...

}

Проблема здесь в том, что клиент должен убедиться, что используется правильная реализация APIClient и APIParser (они должны совпадать)

Ответы [ 2 ]

2 голосов
/ 09 июля 2019

Ваши требования кажутся достаточно хорошими для шаблона Abstract Factory GoF , потому что как только вы создаете конкретную фабрику, а ваш код только создает экземплярыклиент и парсер через эту фабрику, невозможно будет по ошибке получить несовпадающий набор экземпляров клиент / парсер.

AbstractFactory - это объект, который твой клиент использует для создания экземпляров пар клиент / парсер:

interface AbstractFactory {
    APIParser createAPIParser();
    APIClient createAPIClient();    
}

interface APIParser {} 
interface APIClient {}

Бетонные заводы могут предоставить совпадающие пары (возможно, вы сможете повторно использовать экземпляры продукта, но я сохранил это просто):

class ConcreteFactoryA implements AbstractFactory {

    public APIParser createAPIParser() { return new APIParserA(); }
    public APIClient createAPIClient() { return new APIClientA(); }
}

class ConcreteFactoryB implements AbstractFactory {

    public APIParser createAPIParser() { return new APIParserB(); }
    public APIClient createAPIClient() { return new APIClientB(); }
}

Для полноты здесь приведены описания конкретных продуктов:

class APIParserA implements APIParser {}
class APIParserB implements APIParser {}
class APIClientA implements APIClient {}
class APIClientB implements APIClient {}

Пример кода клиента:

AbstractFactory factory = new ConcreteFactoryA();
APIClient client = factory.createAPIClient();
APIParser parser = factory.createAPIParser();
1 голос
/ 09 июля 2019

Что вы можете сделать, это добавить параметр типа в ваши классы.

// wrapper for your json
public class APIResult<T extends APIClient<T>> {

    private final String json;

    public APIResult(String json) {
        this.json = json;
    }

    public String getJson() {
        return this.json;
    }
}
// client always returns a result with itself as a type
public interface APIClient<T extends APIClient<T>> {

    APIResult<T> makeRequest();
}
// parser only handles the implementation specific results of one client
public interface APIParser<T extends APIClient<T>> {

    String getTemperature(APIResult<T> result);
}
public class APIClientA implements APIClient<APIClientA> {

    public APIResult<APIClientA> makeRequest() {
        // must return a result with this type
    }
}
public class APIParserA implements APIParser<APIClientA> {

    public String getTemperature(APIResult<APIClientA> result) {
        // only accepts results from one specific client
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...