【问题标题】:Android: how to use Code to interface design pattern to have multiple implementations of network call libraries(Retrofit or volley)Android:如何使用 Code 接口设计模式来实现网络调用库的多种实现(Retrofit 或 volley)
【发布时间】:2017-02-12 18:15:31
【问题描述】:

我正在从 Head First Design Patterns 学习设计模式,我遇到的第一个模式是“代码到接口”。现在我想在我的 android 应用程序中使用该模式。我的应用程序包含很多 api 调用。我是使用 Retrofit 进行网络调用。因此,考虑到类似这样的场景,我使用了该设计模式:
1. 假设将来我需要从 Retrofit 转移到 volley 或任何其他网络库。
2. 所以我创建了一个带有从服务器获取数据的方法的接口,并创建了一个实现该接口的类。实现的方法包括从服务器获取数据的改造代码。
3. 现在如果我想使用 volley,我将创建一个实现接口的新类,并使用 volley 代码从服务器检索数据。
代码是这样的

更新

改造特定接口

public interface RetrofitApi {
    @GET
    Call<ResponseBody> getDataFromServer(@Url String url);
}

更新

界面

具有多个网络调用库实现的通用接口(这里我正在使用改造,所以我创建了一个实现此接口的类 NetworkCallsRetrofitImpl。如果我想切换到 volley,我将创建另一个具有 volley 实现的类并实现此接口)

public interface NetworkCallsApi {
    String getDataFromServer(Activity activity,String url,String Callback);
}

改造实施

public class NetworkCallsRetrofitImpl implements NetworkCallsApi{

private Retrofit retrofit;

@Override
public String getDataFromServer(Activity activity, String url, String Callback) {

    retrofit = new Retrofit.Builder()
            .baseUrl(StringConstants.ROOT_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    RetrofitApi apiCalls = retrofit.create(RetrofitApi.class);

    Call<ResponseBody> call = apiCalls.getDataFromServer(url);

    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

            Method method = null;
            try {
                method = fragment.getClass().getDeclaredMethod(
                        Callback, new Class[]{String.class});
                method.invoke(fragment, response.body().string());
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {

        }
    });
    return null;
}
}

ServiceCalls.java

public class ServiceCalls {

public static ServiceCalls serviceCalls;
public NetworkCallsApi networkCallsimpl;

public static ServiceCalls getInstance(){

    if(serviceCalls == null){
        serviceCalls = new ServiceCalls();
    }
    return serviceCalls;
}

public void setNetworkCallsimpl(NetworkCallsApi networkCallsimpl) {
    this.networkCallsimpl = networkCallsimpl;
}

public String getDataFromServer(Activity activity, String url, String callback){
    networkCallsimpl.getDataFromServer(activity,url,callback);
    return null;
}
}

MainFragment 代码:

public class StatusFragment extends Fragment {    

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //Setting the implementation
    ServiceCalls.getInstance().setNetworkCallsimpl(new NetworkCallsRetrofitImpl());
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    view = inflater.inflate(R.layout.fragment_pnr_status,container,false);

    try{
        init();
    }catch(Exception e){

    }
    return view;
}

private void init() {

    ok.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            setUrlKeysAndValues();
            ServiceCalls.getInstance().getDataFromServer(getActivity()
                    ,Utils.getInstance().buildUrl(urlKeys,urlValues),"onResponse");
        }
    });

}

public void onResponse(String response){

    String x = response;
    try {
        JSONObject jsonObject = new JSONObject(x);
        String name = jsonObject.getJSONObject("train").getString("name");
        String temp = jsonObject.getJSONObject("train").getString("name");
    } catch (JSONException e) {
        e.printStackTrace();
    }
}
}

现在我的问题是“我是否正确实现了该设计模式”。如果没有,我需要做哪些更改。在 MainFragment 代码的 onCreate 中,我正在对实现进行硬编码。如何更好地应用接口设计模式的代码场景。谢谢。

更新

这里的'String Callback'只是接收响应后调用的方法名。这个方法写在片段类中,视图必须更新。我正在使用Java反射调用这个方法。

【问题讨论】:

标签: java android design-patterns


【解决方案1】:

1) 带有回调的方法应该没有返回类型。无论如何你都返回 null ,所以让它们无效。

2) 您最终需要返回 UI 中的响应来更新您的视图,因此您应该将回调作为 Callback 类传递,而不是某些 String callback

3) 不需要为每次调用您的方法更新该私有字段。

4) 你不需要 Activity 来发出网络请求(我想回到第 2 点)

5) 我很确定 Retrofit 使用注释来处理 URL,所以我不确定我在 getDataFromServer(url) 看到参数的用途。


您更新后的代码将如下所示。

注意:这不是“编程接口”或任何“设计模式”的展示,它只是“干净的代码”(恕我直言)。

Retrofit 已经强制执行“编程接口”模式,无论如何,尽管Retrofit.create 方法。

public class NetworkCallsRetrofitImpl implements NetworkCallsApi{

    private final Retrofit retrofit;

    public NetworkCallsRetrofitImpl() {
        retrofit = new Retrofit.Builder()
            .baseUrl(StringConstants.ROOT_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    }

    public void getDataFromServer(String url, Callback<ResponseBody> cb) {
        retrofit.create(RetrofitApi.class)
            .getDataFromServer(url)
            .enqueue(cb);
    }
}

// This method seems really pointless, by the way... 
public void getDataFromServer(String url, Call<ResponseBody> callback){
    networkCallsimpl.getDataFromServer(url,callback);
}

public class StatusFragment extends Fragment implements Callback<ResponseBody> {   

    private ServiceCalls serviceCalls;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Setting the implementation
        serviceCalls = ServiceCalls.getInstance();
        serviceCalls.setNetworkCallsimpl(new NetworkCallsRetrofitImpl());
    }

    private void updateStatus() {
        serviceCalls.getDataFromServer("http://site.example/status", this);
    }

    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        String response = response.body().toString();
        Toast.makeText(getActivity(), response, TOAST.LENGTH_SHORT).show();
    }

     @Override
     public void onFailure(Call<ResponseBody> call, Throwable t) {
         Log.e("err", t.getMessage());
     }
}

【讨论】:

  • 感谢回复。关于字符串回调和改造等接口的问题我已经更新了一些观点。请看一下。
  • 使用反射是不好的,我不建议这样做(除非你无法避免)
  • 如果我想使用 volley 实现而不是改造呢?
  • 在我看来,你真的不会混合或切换。并不是说做不到。只是没有充分的理由。 Volley 有 RequestQueue 的概念,而改造没有,所以你必须把它放在某个地方。
  • 而且 Volley 的 Response.Listener 类与 Retrofit 的 Callback 类不兼容,所以即使你想切换,你也需要将它们包装在你自己的抽象回调中
猜你喜欢
  • 2013-06-06
  • 2017-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-17
  • 1970-01-01
相关资源
最近更新 更多