到目前爲止,多線程下載功能設計、編寫、優化工作已經完成,但是網絡框架編寫工作並沒有完成,此篇將完成Http核心架構,編寫的新功能還是圍繞在http請求上,涉及到的知識點:
- httpHeader的接口定義和實現
- http請求頭和響應頭訪問編寫
- http狀態碼定義
- http中的 response封裝、request接口封裝和實現
(建議閱讀此篇文章之前,需理解前兩篇文章的講解,此係列文章是環環相扣,不可缺一,鏈接如下:)
優雅設計封裝基於Okhttp3的網絡框架(一):Http網絡協議與Okhttp3解析
優雅設計封裝基於Okhttp3的網絡框架(二):多線程下載功能原理設計 及 簡單實現
優雅設計封裝基於Okhttp3的網絡框架(三):多線程下載功能核心實現 及 線程池、隊列機制解析
優雅設計封裝基於Okhttp3的網絡框架(四):多線程下載添加數據庫支持(greenDao)及 進度更新
優雅設計封裝基於Okhttp3的網絡框架(五):多線程、單例模式優化 及 volatile、構建者模式使用解析
一. Http核心架構實現
下面將完成網絡框架核心架構,考慮到程序的擴展性,首要編寫的是接口,採用設計模式將相關的接口預留出來。
1. HttpHeader的接口定義和實現
(1)NameValueMap鍵值對接口
在定義接口之前,需要先定義一個鍵值對接口NameValueMap,繼承Map接口,提供一些相關接口訪問,實現比較簡單,代碼如下:
public interface NameValueMap<K, V> extends Map<K, V> {
String get(String name);
void set(String name, String value);
void setAll(Map<String, String> map);
}
(2)HttpHeader實現NameValueMap
HttpHeader是實現了整個Http請求的接口,該類在定義時實現NameValueMap接口後,需要實現很多方法。既然HttpHeader實現了鍵值對接口,所以在其內部需要維護一個private Map<String, String> mMap
,此時可以根據此HashMap來完善待實現方法。
/**
* @function Http請求、響應頭部字段訪問封裝
* @author lemon Guo
*/
public class HttpHeader implements NameValueMap<String, String> {
private Map<String, String> mMap = new HashMap<>();
/*
* 以下都是實現Map接口後需要實現的方法
* */
@Override
public String get(String name) {
return mMap.get(name);
}
@Override
public void set(String name, String value) {
mMap.put(name, value);
}
@Override
public void setAll(Map<String, String> map) {
mMap.putAll(map);
}
@Override
public int size() {
return mMap.size();
}
@Override
public boolean isEmpty() {
return mMap.isEmpty();
}
@Override
public boolean containsKey(Object o) {
return mMap.containsKey(o);
}
@Override
public boolean containsValue(Object value) {
return mMap.containsValue(value);
}
@Override
public String get(Object o) {
return mMap.get(o);
}
@Override
public String put(String key, String value) {
return mMap.put(key, value);
}
@Override
public String remove(Object key) {
return mMap.remove(key);
}
@Override
public void putAll(Map<? extends String, ? extends String> map) {
mMap.putAll(map);
}
@Override
public void clear() {
mMap.clear();
}
......
}
2. Http請求頭和響應頭訪問編寫
下面就是對Http請求頭接口上的訪問和包裝,首先需要知道Http請求頭包含的內容,但是Http請求頭、響應頭所包含的內容是比較多的,這裏只在此封裝較爲常見的字段:
/**
* @function Http請求、響應頭部字段訪問封裝
* @author lemon Guo
*/
public class HttpHeader implements NameValueMap<String, String> {
//常用的 Http字段
public final static String ACCEPT = "Accept";
public final static String PRAGMA = "Pragma";
public final static String PROXY_CONNECTION = "Proxy-Connection";
public final static String USER_AGENT = "User-Agent";
public final static String ACCEPT_ENCODING = "accept-encoding";
public final static String CACHE_CONTROL = "Cache-Control";
public final static String CONTENT_ENCODING = "Content-Encoding";
public final static String CONNECTION = "Connection";
public final static String CONTENT_LENGTH = "Content-length";
public static final String CONTENT_TYPE = "Content-Type";
private Map<String, String> mMap = new HashMap<>();
/*
* 以上Http字段的get/set方法
* */
public String getAccept() {
return get(ACCEPT);
}
public void setAccept(String value) {
set(ACCEPT, value);
}
......
/*
* 以下都是實現Map接口後需要實現的方法
* */
......
}
以上已經封裝完成HttpHeader類——Http頭部相關字段的訪問。接下來還需要對Http請求方式進行一個簡單的封裝,除了常用的GET、POST方式還有其它5種,通過一個枚舉進行封裝即可。代碼如下:
/**
* @function Http請求方式封裝
* @author lemon Guo
*/
public enum HttpMethod {
GET, POST, TRACE, PUT, DELETE, CONNECTION, OPTIONS
}
3. Http狀態碼定義
Http的狀態碼非常多,分佈於100~600,根據狀態碼也分成了幾種不同的類型,這裏也是封裝每種類型中較爲常見的,同樣採用枚舉方式。
- 爲HttpStatus類提供構造方法,參數爲狀態碼和含義。
- 聲明狀態碼枚舉類型。
- 對外提供方法
isSuccess
,通過判斷字節碼返回代表請求是否成功的boolean值 - 對外提供方法
getValue
,通過傳入的參數狀態碼數字,返回狀態碼枚舉類型。
/**
* @function Http狀態碼封裝
* @author lemon Guo
*/
public enum HttpStatus {
CONTINUE(100, "Continue"),
SWITCHING_PROTOCOLS(101, "Switching Protocols"),
OK(200, "OK"),
CREATED(201, "Created"),
Accepted(202, "Accepted "),
NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information"),
NO_CONTENT(204, "No Content"),
RESET_CONTENT(205, "Reset Content"),
MULTIPLE_CHOICES(300, "Multiple Choices"),
MOVED_PERMANENTLY(301, "Moved Permanently"),
FOUND(302, "Found"),
SEE_OTHER(303, "See Other"),
USE_PROXY(305, "Use Proxy "),
UNUSED(306, "Unused"),
TEMPORARY_REDIRECT(307, "Temporary Redirect"),
BAD_REQUEST(400, "Bad Request"),
PAYMENT_REQUIRED(402, "Payment Required"),
FORBIDDEN(403, "Forbidden"),
NOT_FOUND(404, "Not_Found"),
METHOD_NOT_ALLOWED(405, "Method Not Allowed "),
NOT_ACCEPTABLE(406, "Not Acceptable"),
REQUEST_TIMEOUT(408, "Request Timeout"),
CONFLICT(409, "Conflict"),
GONE(410, "Gone"),
LENGTH_REQUIRED(411, "Length Required"),
PAYLOAD_TOO_LARGE(413, "Payload Too Large"),
URI_TOO_LONG(414, "URI Too Long"),
UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type Server Error"),
FAILED(417, "Failed Server Error"),
UPGRADE_REQUIRED(426, "Upgrade Required"),
INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
NOT_IMPLEMENTED(501, "Not Implemented"),
BAD_GATEWAY(502, "Bad_Gateway"),
SERVICE_UNAVAILABLE(503, "Service Unavailable"),
GATEWAY_TIMEOUT(504, "Gateway Timeout"),
HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version Not Supported ");
private int mCode;
private String mMessage;
private HttpStatus(int code, String message) {
this.mCode = code;
this.mMessage = message;
}
public boolean isSuccess() {
int value = mCode / 100;
if (value == 2) {
return true;
}
return false;
}
public static HttpStatus getValue(int value) {
for (HttpStatus httpStatus : values()) {
if (value == httpStatus.mCode) {
return httpStatus;
}
}
return null;
}
}
二. Http中Response、Request封裝實現
在第一大點編碼中的類與接口實現比較基礎,難度不大,更像是實現Http核心框架前做的準備,所以說前期接口設計封裝直接決定整個程序的擴展性,需謹慎考慮全面。而接下來將對Http中的Response響應、Request請求進行封裝。
1. Response接口封裝
首先思考一下Response接口中需要封裝的方法,狀態碼和body的獲取必不可少,另外可以考慮狀態碼信息獲取、字節長度獲取方法。
(1)Header
在封裝Response之前還需要先封裝一個接口 —– Header,它是對所有響應頭、請求頭的封裝,而接口中只有一個getHeaders
方法,意味着響應頭、請求頭都會對其實現。代碼如下:
/**
* @function 對所有響應頭、請求頭的封裝
* @author lemonGuo
*/
public interface Header {
HttpHeader getHeaders();
}
(2)HttpResponse接口
該接口繼承於Header、Closeable接口,組成爲:
- 必須要有獲取狀態碼
getStatus()
方法、獲取Body輸入流getBody()
方法、關閉輸入流close()
方法。 - 其次爲了考慮全面,新增了獲取狀態碼代表信息
getStatusMsg()
方法、獲取字節長度getContentLength()
方法
/**
* @funtion Http響應接口
* @author nate
*/
public interface HttpResponse extends Header, Closeable {
HttpStatus getStatus();
String getStatusMsg();
InputStream getBody() throws IOException;
void close();
long getContentLength();
}
(3)抽象類AbstractHttpResponse
以上HttpResponse 接口定義好之後,可以定義響應類實現,可是在此之前還需要定義一個抽象類AbstractHttpResponse,由它來實現HttpResponse 接口。
抽象類的好處
抽象類可以擁有自己的成員變量和已實現的方法,比接口的功能更加豐富。在封裝框架過程中,可藉由抽象類來實現一些內部的方法,更易擴展。
編碼實現
在此抽象類中處理響應數據時,需要多判斷一點:即是否爲壓縮數據,若是則對數據流進行處理後再作返回。該抽象類主要是對響應數據多做了一層判斷,相當於一個過濾網。
爲了處理壓縮這種情況,該抽象類實現了HttpResponse 接口中的getBody()
、close()
,做了一些共性的預處理操作,同時爲具體實現的子類留出了getBodyInternal()
、closeInternal()
抽象方法。
/**
* @function AbstractHttpResponse 數據響應抽象類(繼承HttpResponse接口)
* @author lemon guo
*/
public abstract class AbstractHttpResponse implements HttpResponse {
private static final String GZIP = "gzip";
private InputStream mGzipInputStream;
@Override
public void close() {
if (mGzipInputStream != null) {
try {
mGzipInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
closeInternal();
}
@Override
public InputStream getBody() throws IOException {
InputStream body = getBodyInternal();
if (isGzip()) {
return getBodyGzip(body);
}
return body;
}
protected abstract InputStream getBodyInternal() throws IOException;
protected abstract void closeInternal();
private InputStream getBodyGzip(InputStream body) throws IOException {
if (this.mGzipInputStream == null) {
this.mGzipInputStream = new GZIPInputStream(body);
}
return mGzipInputStream;
}
private boolean isGzip() {
String contentEncoding = getHeaders().getContentEncoding();
if (GZIP.equals(contentEncoding)) {
return true;
}
return false;
}
}
(4)實現類OkHttpResponse
回顧以上,已完成的接口、抽象類都是在爲Http響應實現類做準備,最後定義實現類OkHttpResponse,繼承抽象類AbstractHttpResponse,實現父類的方法:
- 實現類內部定義兩個重要成員變量:響應類mResponse和Http字段訪問類mHeaders 。
- 爲實現類提供構造方法,參數爲響應類Response。
- 實現類內部待實現的方法具體編碼都依賴於以上兩個成員變量。
代碼量雖然不少,但是實現簡單,查看即可理解,代碼如下:
/**
* @funtion: 實現類OkHttpResponse
* @author lemon Guo
*/
public class OkHttpResponse extends AbstractHttpResponse {
private Response mResponse;
private HttpHeader mHeaders;
public OkHttpResponse(Response response) {
this.mResponse = response;
}
@Override
protected InputStream getBodyInternal() {
return mResponse.body().byteStream();
}
@Override
protected void closeInternal() {
mResponse.body().close();
}
@Override
public HttpStatus getStatus() {
return HttpStatus.getValue(mResponse.code());
}
@Override
public String getStatusMsg() {
return mResponse.message();
}
@Override
public long getContentLength() {
return mResponse.body().contentLength();
}
@Override
public HttpHeader getHeaders() {
if (mHeaders == null) {
mHeaders = new HttpHeader();
}
for (String name : mResponse.headers().names()) {
mHeaders.set(name, mResponse.headers().get(name));
}
return mHeaders;
}
}
2. HttpRequest接口封裝和實現
接下來完成Http請求上的接口設計封裝,其實在真正瞭解以上Response的系列接口、抽象類、實現類設計實現後,會發現兩者的“套路”其實很相似。
(1)HttpRequest接口
首先來思考接口中的方法,一個請求很關鍵的是請求頭,然後是請求方式,最後是請求中傳遞的參數信息。
前期考慮封裝很重要,需設計全面,代碼實現如下:
/**
* @funtion HttpRequest接口設計
* @author nate
*/
public interface HttpRequest extends Header {
HttpMethod getMethod();
URI getUri();
OutputStream getBody();
HttpResponse execute() throws IOException;
}
(2)抽象類AbstractHttpRequest
如上,接口定義完之後,定義抽象類繼承該接口,實現了HttpResponse 接口中的getBody()
、getHeaders()
、execute()
做一些共性的處理操作,同時爲具體實現的子類留出了executeInternal(HttpHeader mHeader)
、getBodyOutputStream()
抽象方法。
同樣爲了考慮壓縮情況,在實現父類的方法中需要判斷當前請求過程中是否支持Zip壓縮,根據判斷結果來決定是否需要進一步處理輸出流。
請求、響應抽象類中的壓縮判斷代碼相同,都是爲了考慮壓縮情況,在接口的基礎上多做了一層封裝。編碼實現並不難,如下:
/**
* @function AbstractHttpRequest 數據響應抽象類(繼承HttpRequest接口)
* @author lemon guo
*/
public abstract class AbstractHttpRequest implements HttpRequest {
private static final String GZIP = "gzip";
private HttpHeader mHeader = new HttpHeader();
private ZipOutputStream mZip;
private boolean executed;
@Override
public HttpHeader getHeaders() {
return mHeader;
}
@Override
public OutputStream getBody() {
OutputStream body = getBodyOutputStream();
if (isGzip()) {
return getGzipOutStream(body);
}
return body;
}
private OutputStream getGzipOutStream(OutputStream body) {
if (this.mZip == null) {
this.mZip = new ZipOutputStream(body);
}
return mZip;
}
private boolean isGzip() {
String contentEncoding = getHeaders().getContentEncoding();
if (GZIP.equals(contentEncoding)) {
return true;
}
return false;
}
@Override
public HttpResponse execute() throws IOException {
if (mZip != null) {
mZip.close();
}
HttpResponse response = executeInternal(mHeader);
executed = true;
return response;
}
protected abstract HttpResponse executeInternal(HttpHeader mHeader) throws IOException;
protected abstract OutputStream getBodyOutputStream();
}
(3)請求流抽象處理BufferHttpRequest
到這裏你會發現接下來不是應該創建實現類麼?請求的封裝在此之前還需要再對抽象類進行一層封裝—–BufferHttpRequest,繼承於AbstractHttpRequest,在其中對請求流多做一步操作:
- 內部維護一個成員變量:輸出字節流ByteArrayOutputStream 。
- 在實現於父類的
getBodyOutputStream
方法中將成員變量輸出流返回出去。 - 在實現於父類的
executeInternal(HttpHeader header)
方法中將成員變量內存數據轉換爲字節數組類型,即請求時傳遞參數的信息,再定義抽象方法將HttpHeader、字節數組兩個參數傳出。相當於在原理基礎上對輸出流多做了一步處理:轉換爲字節數組類型。
代碼實現如下:
/**
* @funtion 請求流抽象處理BufferHttpRequest
* @author lemon Guo
*/
public abstract class BufferHttpRequest extends AbstractHttpRequest {
private ByteArrayOutputStream mByteArray = new ByteArrayOutputStream();
protected OutputStream getBodyOutputStream() {
return mByteArray;
}
protected HttpResponse executeInternal(HttpHeader header) throws IOException {
byte[] data = mByteArray.toByteArray();
return executeInternal(header, data);
}
protected abstract HttpResponse executeInternal(HttpHeader header, byte[] data) throws IOException;
}
(4)實現類OkHttpRequest
由於請求不同於響應的特殊性,需要考慮到頭部信息,在封裝兩次抽象類後,最後編寫實現類OkHttpRequest。此類繼承於BufferHttpRequest ,具體實現爲:
- 定義成員變量OkHttpClient及參數HttpMethod、Url來實現Okhttp的請求過程。
- 提供構造方法初始化以上3個成員變量。
- 實現抽象方法
getMethod()
、getUri()
。(這兩個抽象方法實現簡單,只需返回成員變量即可) - 實現抽象方法
executeInternal(HttpHeader header, byte[] data)
:
- 首先需要判斷請求方式是否爲POST,若是則意味着需要處理RequestBody,將客戶端傳遞的data參數封裝到RequestBody其中。
- 創建請求Request.Builder,傳入URL、請求方式、RequestBody參數。
- 接着對header進行處理,循環該參數將所有請求頭封裝至Request.Builder
- 最後封裝完畢,調用成員變量OkHttpClient進行請求,獲取到響應數據Response。
- 創建上一點封裝好的響應實現類HttpResponse,將響應數據傳入其構造方法,最後將響應實現類HttpResponse返回出去即可。
此部分較爲重要,一定要將邏輯整理清楚,代碼實現如下:
/**
* @function 實現類OkHttpRequest
* @author lemon guo
*/
public class OkHttpRequest extends BufferHttpRequest {
private OkHttpClient mClient;
private HttpMethod mMethod;
private String mUrl;
public OkHttpRequest(OkHttpClient client, HttpMethod method, String url) {
this.mClient = client;
this.mMethod = method;
this.mUrl = url;
}
@Override
protected HttpResponse executeInternal(HttpHeader header, byte[] data) throws IOException {
boolean isBody = mMethod == HttpMethod.POST;
RequestBody requestBody = null;
if (isBody) {
requestBody = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), data);
}
Request.Builder builder = new Request.Builder().url(mUrl).method(mMethod.name(), requestBody);
for (Map.Entry<String, String> entry : header.entrySet()) {
builder.addHeader(entry.getKey(), entry.getValue());
}
Response response = mClient.newCall(builder.build()).execute();
System.out.println("fuck "+response.body().contentLength());
return new OkHttpResponse(response);
}
@Override
public HttpMethod getMethod() {
return mMethod;
}
@Override
public URI getUri() {
return URI.create(mUrl);
}
}
3. 測試
在創建的module文件夾下會自動生成一個test文件夾,供開發人員測試所用,在這裏可以編寫一個簡單的網絡代碼來測試以上編碼工作是否正確,代碼如下:
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
OkHttpClient client = new OkHttpClient();
OkHttpRequest request = new OkHttpRequest(client, HttpMethod.GET, "http://www.baidu.com");
HttpResponse response = request.execute();
String content = null;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody()));
while ((content = bufferedReader.readLine()) != null){
System.out.println(content);
}
response.close();
}
}
結果顯示
以上代碼邏輯爲GET方式請求百度,打印出請求到的資源數據,成功顯示,證明以上編碼無誤。
三. 工廠模式封裝HttpReques創建
此部分將對HttpRequest對象進行封裝,以上工作對於網絡框架而言是底層實現,那具體的網絡請求是調用OkhttpRequest來完成,但是此次封裝的網絡框架不僅支持Okhttp網絡框架請求方式,還支持原生UrlConnection請求,所以考慮到擴展性,完成原生請求,只需繼承HttpReques接口實現功能即可,但是對於上層業務調用,還是要對請求對象進行封裝。
通過一種機制來封裝HttpReques對象給上層調用,對於上層而言只需獲取HttpReques對象即可,至於該對象是通過Okhttp還是UrlConnection獲取並不關注。
1. 接口HttpRequestFactory
通過此接口的名字便知它內部採用的是工廠模式,而方法就是獲取HttpReques對象:
/**
* @function 接口HttpRequestFactory(獲取HttpRequest對象)
* @author lemon Guo
*/
public interface HttpRequestFactory {
HttpRequest createHttpRequest(URI uri, HttpMethod method) throws IOException;
}
工廠設計模式
工廠設計模式可以解決的問題:
- 不會向上層曝露對象創建的複雜過程,只提供結果。
- 工廠模式是典型的解耦式設計,使職責單一化。
類圖
結合此類圖至編寫的接口:
- HttpRequestFactory就是工廠模式中的Creator
- 接口中返回的HttpRequest 對象就是工廠模式中的Product
- 下面就需要創建實現類繼承接口來“生產”Product,此實現類相當於工廠模式中的ConcreteCreator
2. 實現類
通過以上結合工廠模式的分析後,得知此類就是“生產”HttpRequest 對象的具體實現類,它繼承於HttpRequestFactory 接口,具體實現:
- 定義成員變量OkhttpClient
- 爲此類提供構造方法初始化成員變量
- 實現接口中的
createHttpRequest
方法,即創建OkHttpRequest 對象並返回。 - 再提供一些基本方法
setConnectionTimeOut
設置請求超時時間,setReadTimeOut
、setWriteTimeOut
設置讀寫時間。(若有其他需求,此處可繼續增加)
/**
* @function 實現類OkHttpRequestFactory(返回HttpRequest對象)
* @author lemon Guo
*/
public class OkHttpRequestFactory implements HttpRequestFactory {
private OkHttpClient mClient;
public OkHttpRequestFactory() {
this.mClient = new OkHttpClient();
}
public OkHttpRequestFactory(OkHttpClient client) {
this.mClient = client;
}
public void setReadTimeOut(int readTimeOut) {
this.mClient = mClient.newBuilder().
readTimeout(readTimeOut, TimeUnit.MILLISECONDS).
build();
}
public void setWriteTimeOut(int writeTimeOut) {
this.mClient = mClient.newBuilder().
writeTimeout(writeTimeOut, TimeUnit.MILLISECONDS).
build();
}
public void setConnectionTimeOut(int connectionTimeOut) {
this.mClient = mClient.newBuilder().
connectTimeout(connectionTimeOut, TimeUnit.MILLISECONDS).
build();
}
@Override
public HttpRequest createHttpRequest(URI uri, HttpMethod method) {
return new OkHttpRequest(mClient, method, uri.toString());
}
}
3. 供上層調用HttpRequestProvider
接下來需要將OkHttpRequestFactory 的具體實現再做一次封裝供上層使用,創建一個類HttpRequestProvider :
- 定義成員變量HttpRequestFactory,用於創建HttpRequest對象。
- 提供構造方法來初始化成員變量。注意這裏會判斷項目中是否使用Okhttp:
- 若是,則創建OkHttpRequestFactory
- 若不是,意味着請求需依賴原生UrlConnction,使用原生的Factory(後續會編寫)。
- 提供方法
getHttpRequest(URI uri, HttpMethod httpMethod)
,底層會調用HttpRequestFactory來創建HttpRequest對象。
/**
* @function 封裝請求HttpRequestProvider,供上層調用
* @author lemon Guo
*/
public class HttpRequestProvider {
private static boolean OKHTTP_REQUEST = Utills.isExist("okhttp3.OkHttpClient", HttpRequestProvider.class.getClassLoader());
private HttpRequestFactory mHttpRequestFactory;
public HttpRequestProvider() {
if (OKHTTP_REQUEST) {
mHttpRequestFactory = new OkHttpRequestFactory();
} else {
mHttpRequestFactory = new OriginHttpRequestFactory();
}
}
public HttpRequest getHttpRequest(URI uri, HttpMethod httpMethod) throws IOException {
return mHttpRequestFactory.createHttpRequest(uri, httpMethod);
}
public HttpRequestFactory getHttpRequestFactory() {
return mHttpRequestFactory;
}
public void setHttpRequestFactory(HttpRequestFactory httpRequestFactory) {
mHttpRequestFactory = httpRequestFactory;
}
}
最後,供給上層調用的就是HttpRequestProvider 類,它可以根據不同的條件創建不同Http請求library,這樣便實現多個library類庫切換的條件判斷使用。
四. 總結
1. 本篇總結
以上截圖顯示着此篇博文完成的編碼內容,看起來編碼量很多,但是實現起來邏輯並不複雜。其中含有大量的接口、抽象類,這些都是在爲程序拓展性做準備,在下一篇博文中將添加新的類庫請求支持,你會發現在此基礎上只需增加3個類即可,充分體現出了程序的擴展性。
我們編寫的順序基本是 接口、枚舉 –> 抽象類 –>實現類,
- 在第一點準備工作中完成了HttpHeader的設計實現、Http請求頭和響應頭訪問編寫、Http狀態碼封裝,這些並不複雜,只是最基本的封裝思想。
- 在第二點中主要對Http中的Request、Response進行設計封裝,這裏爲了程序擴展性邏輯稍顯複雜,先從接口開始定義,然後在此基礎上定義抽象類實現接口,在其內部進行共性操作,再留出抽象方法。
- 第三點在現有的請求方式上再次封裝,採用工廠模式,提供最簡潔方法供上層調用。
此篇文章完成的部分還是有些多,需將邏輯捋清楚,但每個類實現並不難,重要的是它們之間的封裝關係,可對應以下代碼理解。
2. 下篇預告
在下一篇博文中將添加新功能——原生請求的類庫支持,你會發現在此基礎上只需增加3個類即可,充分體現出了程序的擴展性。新增功能如下:
- 原生HttpUrlConnction請求和響應
- 業務層多線程分發處理
- 移除請求
- 請求成功類型轉換包裝處理
若有錯誤,虛心指教~