You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何抽象仅表名存在差异的Retrofit服务接口?

Abstracting Retrofit Services with Shared Path Patterns

Great question! Since Retrofit doesn’t let you pass dynamic values directly into the @GET/@POST annotations, we can use a combination of generic interfaces and Java default methods to abstract away duplicate code while keeping your original service interface signatures intact. Here’s how to do it:

Step 1: Create a Generic Base Interface

First, define a base interface that uses Retrofit’s @Path annotation to handle the variable resource name (like "reminder" or "file"). This interface will hold the core API methods with the dynamic path segment:

import io.reactivex.Observable;
import retrofit2.Response;
import retrofit2.http.GET;
import retrofit2.http.HeaderMap;
import retrofit2.http.POST;
import retrofit2.http.Path;

interface GenericResourceService {
    // Dynamic path segment: {resource} gets replaced with "reminder" or "file"
    @GET("{resource}/list")
    Observable<Response<Reminder>> getList(
        @Path("resource") String resourceName,
        @HeaderMap Map<String, String> headerMap
    );

    @POST("{resource}/ins")
    Observable<Response<Reminder>> ins(
        @Path("resource") String resourceName,
        @HeaderMap Map<String, String> headerMap
    );
}

Step 2: Extend the Base Interface for Specific Services

Now, create your original service interfaces by extending the generic base. Use Java default methods to hardcode the resource name for each service—this keeps the original method signature exactly the same, so existing callers don’t need any changes:

// ReminderService with fixed "reminder" resource
interface ReminderService extends GenericResourceService {
    @Override
    default Observable<Response<Reminder>> getList(@HeaderMap Map<String, String> headerMap) {
        return super.getList("reminder", headerMap);
    }

    @Override
    default Observable<Response<Reminder>> ins(@HeaderMap Map<String, String> headerMap) {
        return super.ins("reminder", headerMap);
    }
}

// FileService with fixed "file" resource
interface FileService extends GenericResourceService {
    @Override
    default Observable<Response<Reminder>> getList(@HeaderMap Map<String, String> headerMap) {
        return super.getList("file", headerMap);
    }

    @Override
    default Observable<Response<Reminder>> ins(@HeaderMap Map<String, String> headerMap) {
        return super.ins("file", headerMap);
    }
}

Why This Works

  • Retrofit’s @Path: This annotation safely replaces the {resource} placeholder in the URL with the specified string, resulting in endpoints like reminder/list or file/ins.
  • Default Methods: These let us override the base interface’s methods to inject the specific resource name, while preserving the method signature your code already relies on.
  • Code Reusability: All shared logic lives in the base interface—if you need to add a new method (like delete), you only add it once, and all child services inherit it automatically.

Alternative: Factory-Based Approach

If you prefer not to use default methods, you can create a factory class that generates preconfigured instances of the generic interface:

class ServiceFactory {
    private final Retrofit retrofit;

    public ServiceFactory(Retrofit retrofit) {
        this.retrofit = retrofit;
    }

    public GenericResourceService createReminderService() {
        return createService("reminder");
    }

    public GenericResourceService createFileService() {
        return createService("file");
    }

    private GenericResourceService createService(String resourceName) {
        return new GenericResourceService() {
            @Override
            public Observable<Response<Reminder>> getList(@HeaderMap Map<String, String> headerMap) {
                return retrofit.create(GenericResourceService.class).getList(resourceName, headerMap);
            }

            @Override
            public Observable<Response<Reminder>> ins(@HeaderMap Map<String, String> headerMap) {
                return retrofit.create(GenericResourceService.class).ins(resourceName, headerMap);
            }
        };
    }
}

This works too, but the default method pattern is cleaner and more aligned with Retrofit’s interface-first design.


内容的提问来源于stack exchange,提问作者Bisma Frühling

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 13:12:38