对于这种情况,单例、工厂还是其他更好?

发布于 2024-12-29 06:03:54 字数 2903 浏览 1 评论 0原文

我正在尝试找到最好的面向对象方法来做到这一点,我将感谢您的帮助。

我认为最简单的方法是向您展示我是如何做到的,并尝试解释我想要什么(我简化了它):

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 的原因:我在应用程序启动时设置标头,然后我只需执行请求即可。 但我相信让 UsersApiItemsApi 扩展 MyServiceApi 是最好的方法。他们使用 MyServiceApi,但不扩展其功能。 另外,我听说 SingleTon 是反模式的,不利于测试等等。

所以现在我很松散,我不知道该怎么办。你会怎么做?

一个可能的想法是删除 MyServiceApi 的抽象并在其上设置单例,让 UsersApiItemsApi 使用 MyServiceApi code> 但不是通过扩展它,但是我将如何管理 getBaseUrl 呢?

真的非常感谢您的帮助,我真的很感激!

I'm trying to find the best OO way to do this, and I would appreciate your help on it.

I think the simplest way is to show you how I've done it and try to explain what I want after (I simplified it) :

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 the idea, I'm stuck for something.

First of all, I don't know if what I did is correct (in a Java OO way). I think it's not bad, but I lack the experience to be sure.

Second of all, once my project is running, MyServiceApi will keep the same headers, I won't call other API or with other credentials. That's why I thought about the Singleton : I set the headers at my application start, and then I just have to do the request.
But I believe having UsersApi and ItemsApi extending MyServiceApi is the best way to do. They use MyServiceApi, they don't extends its capabilities.
Also, I eard that SingleTon are anti-pattern, bad for tests, etc.

So now I'm loose and I don't know what to do. How would you do that?

A possible idea is to remove the abstract of MyServiceApi and set a Singleton on it, having UsersApi and ItemsApi to use MyServiceApi but not by extending it, but how would I manage the getBaseUrl then ?

Thank you really much for your help, I really appreciate!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

玉环 2025-01-05 06:03:54

使用依赖注入而不是单例。

看起来您正在尝试拥有一个具有基本 URL 并设置标头的服务。

使用依赖注入,创建一个名为 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);
    }
}

您可以做的其他一些事情:

  • 如果您想一致地公开 getBaseUrl,则创建一个 MyServiceApi 和 UsersApi 都实现的接口
  • 有查看有关依赖项的一些信息注射在那里

Use Dependency Injection rather than a Singleton.

It looks like you're trying to have a single service that has a base URL and sets up your headers.

Using Dependency Injection, create a service called MyApiService, much like you have and have UsersApi 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 both MyServiceApi and UsersApi implements if you want to expose getBaseUrl consistently
  • Have a look at some of the information about Dependency Injection out there
怎樣才叫好 2025-01-05 06:03:54

这就是我要写的方式

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

This is how I would 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/";
    }
}
2025-01-05 06:03:54

这只是为了你的意识。如果您使用单例模式,您的 getInstance 方法应该同步。考虑一个有多个线程正在运行的场景。例如,如果一个线程检查实例是否为空,并且由于它为空,它将进入 try 块。假设它停止,第二个线程进入运行状态。实例仍然为空,并且它也有机会进入 try 块。那么最终你将得到两个实例,并且你的单例策略将被破坏

This is just for your awareness. If you are using Singleton pattern your getInstance method should be synchronized. Think a scenario where you have multiple threads running.For an example if one thread checked the instance is null and since it is null it will go inside the try block.Lets say it halts and the second thread comes to running state. And still the instance is null and it also have the opportunity to go inside the try block. then ultimately you will end up with two instances and you Singleton strategy will break

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文