Синглтон, завод или что-то еще лучше для этого случая? - PullRequest
4 голосов
/ 26 января 2012

Я пытаюсь найти лучший ОО способ сделать это, и я был бы признателен за вашу помощь в этом.

Я думаю, что самый простой способ - показать вам, как я это сделал, и попытаться объяснить, чего я хочу после (я упростил это):

abstract public class MyServiceApi {
    private static MyServiceApi instance = null;

    public static <T extends MyServiceApi> T getInstance(Class<T> cls) {
        if (instance == null) {
            try {
                instance = cls.newInstance();
            }
            catch (InstantiationException e) {}
            catch (IllegalAccessException e) {}
        }

        return (T) instance;
    }

    private private HashMap<String, String> headers;

    protected MyServiceApi() {}

    public HashMap<String, String> getHeaders() {
        return headers;
    }

    public void setHeaders(HashMap<String, String> headers) {
        this.headers = headers;
    }

    protected <T extends IMyServiceApiResponse> T send(String url, IMyServiceApiRequest request, Class<T> to) {
        // Do some stuffs

        // IMPORTANT : Also set headers to the request
    }

    protected String getBaseUrl() {
        return "http://api.mywebsite.com/";
    }
}

public class UsersApi extends MyServiceApi {
    public static UsersApi getInstance() {
        return getInstance(UsersApi.class);
    }

    protected UsersApi() {
        super();
    }

    @Override
    protected String getBaseUrl() {
        return super().getBaseUrl() + "Users/";
    }

    // mutliple function that calls a specific URL in the API, and return specifics object based on the call, for example :
    public MyServiceApiUsersResponse getUsers(MyServiceApiUsersRequest request) {
        return send(getBaseUrl() + "get", request, MyServiceApiUsersResponse.class);
    }
}

public class ItemsApi extends MyServiceApi {
    public static ItemsApi getInstance() {
        return getInstance(ItemsApi.class);
    }

    protected ItemsApi() {
        super();
    }

    @Override
    protected String getBaseUrl() {
        return super().getBaseUrl() + "Items/";
    }

    // mutliple function that calls a speicfic URL in the API, and return specifics object based on the call, for example :
    public MyServiceApiItemsResponse getUsers(MyServiceApiItemsRequest request) {
        return send(getBaseUrl() + "get", request, MyServiceApiItemsResponse.class);
    }

}

Теперь, когда у вас есть идея, я застрял на чем-то.

Прежде всего, я не знаю, правильно ли то, что я сделал (в стиле Java OO). Я думаю, что это не плохо, но мне не хватает опыта, чтобы быть уверенным.

Во-вторых, когда мой проект будет запущен, MyServiceApi сохранит те же заголовки, я не буду вызывать другой API или другие учетные данные. Вот почему я подумал об Singleton: я установил заголовки при запуске приложения, а затем мне просто нужно сделать запрос. Но я считаю, что UsersApi и ItemsApi расширение MyServiceApi - лучший способ сделать это. Они используют MyServiceApi, они не расширяют его возможности. Кроме того, я слышал, что SingleTon - это анти-паттерн, плохо подходит для тестов и т. Д.

Так что теперь я свободен и не знаю, что делать. Как бы вы это сделали?

Возможная идея состоит в том, чтобы удалить реферат MyServiceApi и установить для него Singleton, имея UsersApi и ItemsApi для использования MyServiceApi, но не путем его расширения, но как мне тогда управлять getBaseUrl?

Большое спасибо за вашу помощь, я очень ценю!

Ответы [ 3 ]

2 голосов
/ 26 января 2012

Используйте Dependency Injection, а не Singleton.

Похоже, вы пытаетесь создать единый сервис с базовым URL-адресом и настройкой заголовков.

Используя Dependency Injection, создайте службу MyApiService, очень похожую на вашу, и от нее зависят UsersApi и ItemsApi, например:

public class MyServiceApi {

    private final String baseUrl;
    private final HashMap<String, String> headers;

    protected MyServiceApi(String baseUrl, HashMap<String, String> headers) {
        this.baseUrl = baseUrl;
        this.headers = headers;
    }

    protected <T extends IMyServiceApiResponse> T send(String url,
            IMyServiceApiRequest request, Class<T> to) {
        // Do some stuffs

        // IMPORTANT : Also set headers to the request
    }

    protected String getBaseUrl() {
        return baseUrl;
    }
}

public class UsersApi {

    private final MyServiceApi myServiceApi;

    protected UsersApi(MyServiceApi myServiceApi) {
        this.myServiceApi = myServiceApi;
    }

    protected String getBaseUrl() {
        return myServiceApi.getBaseUrl() + "Users/";
    }

    // mutliple function that calls a specific URL in the API, and return
    // specifics object based on the call, for example :
    public MyServiceApiUsersResponse getUsers(
            MyServiceApiUsersRequest request) {
        return myServiceApi.send(getBaseUrl() + "get", request,
                MyServiceApiUsersResponse.class);
    }
}

Несколько других вещей, которые вы можете сделать:

  • Создайте интерфейс, который реализуют и MyServiceApi, и UsersApi, если вы хотите последовательно предоставлять getBaseUrl
  • Посмотрите на некоторую информацию о Внедрение зависимостей там
1 голос
/ 26 января 2012

Это только для вашего осознания. Если вы используете шаблон Singleton, ваш метод getInstance должен быть синхронизирован. Подумайте о сценарии, в котором у вас запущено несколько потоков. Например, если один поток проверил, экземпляр имеет значение null, а поскольку он имеет значение null, он перейдет в блок try. Предположим, он остановился, а второй поток перешел в состояние выполнения. И все же экземпляр является нулевым, и у него также есть возможность войти внутрь блока try. тогда в конечном итоге вы получите два экземпляра, и ваша синглтон-стратегия сломается

1 голос
/ 26 января 2012

Вот как бы я это написал

enum MyServiceApi {
    UsersApi {
        public MyServiceApiUsersResponse getUsers(MyServiceApiUsersRequest request) {
            return send(getBaseUrl() + "Users/get", request, MyServiceApiUsersResponse.class);
        }

    },  ItemsApi {
        // mutliple function that calls a speicfic URL in the API, and return specifics object based on the call, for example :
        public MyServiceApiItemsResponse getUsers(MyServiceApiItemsRequest request) {
            return send(getBaseUrl() + "Items/get", request, MyServiceApiItemsResponse.class);
        }
    };

    private final Map<String, String> headers = new LinkedHashMap<String, String>();

    public Map<String, String> getHeaders() {
        return headers;
    }

    public void setHeaders(HashMap<String, String> headers) {
        this.headers.clear();
        this.headers.putAll(headers);
    }

    public abstract <T extends IMyServiceApiResponse> T send(String url, IMyServiceApiRequest request, Class<T> to);

    protected String getBaseUrl() {
        return "http://api.mywebsite.com/";
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...