Is Singleton, a factory or something even better for this case?

I am trying to find the best OO way to do this, and I would appreciate your help in this.

I think the easiest way is to show you how I did it and try to explain what I want (simplified):

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

Now that you have an idea, I'm stuck on something.

First of all, I don’t know if I did the right thing (in the Java OO way). I think this is not bad, but I do not have enough experience to be sure.

Secondly, when my project is launched, MyServiceApi will keep the same headers, I will not call another API or other credentials. That's why I thought about Singleton: I set the headers when the application started, and then I just had to execute the request. But I believe that UsersApi and ItemsApi extension MyServiceApi is the best way to do it. They use MyServiceApi , they do not expand their capabilities. Also, I'm sure SingleTon are anti-patterns, bad for tests, etc.

So now I am free, and I do not know what to do. How do you do this?

A possible idea is to remove the MyServiceApi abstract and install Singleton on it, having UsersApi and ItemsApi use MyServiceApi , but not an extension, but how would I manage getBaseUrl?

Thank you very much for your help, I am very grateful!

+4
source share
3 answers

This is how I write it

 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/"; } } 
+1
source

Use dependency injection, not singleton.

It looks like you are trying to create one service with a base URL and customize your headers.

Using Dependency Injection, create a service called MyApiService, just like yours, and the users Api and ItemsApi depend on it, as in:

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

A few other things you could do:

  • Create an interface that implements both MyServiceApi and UsersApi if you want to show getBaseUrl in sequence
  • Have a look at some information about Injection Dependency there
+2
source

It is just for your awareness. If you are using the Singleton template, your getInstance method must be synchronized. Think of a scenario where you are working with multiple threads. For example, if one thread is checked, the instance is null, and since it is zero, it will go into the try block. Says that it stops, and the second thread goes into a ready state. And yet the instance is null, and it also has the ability to go into the try block. then you end up with two instances and the Singleton strategy breaks

+1
source

Source: https://habr.com/ru/post/1393154/


All Articles