设计摸式-面向对象的六大原则

版权声明:博主原创欢迎分享学习 https://blog.csdn.net/qXing123456789/article/details/83275587

设计摸式-面向对象的六大原则

  • 单一职责原则
  • 开闭原则
  • 里氏替换原则
  • 依赖倒置原则
  • 接口隔离原则
  • 迪米特原则

本文对上面的面试对象的六大原则,做逐步了解记录,并结合真实项目与Android源码进行分析,那么开工了,兄弟们靠勤劳双手致富吧!

一 单一职责原则

单一职责原则(Single Responsibility Principle),缩写SRP
概述:就一个类而言,应该仅有一个引起它变化的原因.简单理解,一个类中应该是一组相关性很高的函数,数据的封装

以RxVolley为例,打开源码看client文件下的FileRequest,FormRequest,JSonRequest3个请求,从下面3个类我们能够体会,单一职责的实现,两个完全不一样的功能分开抽取到不同的类中,一个类中应该是一组相关性很高的方法,数据的封装.而我们开发则需要根据具体的业务,功能对类型进行相应的拆分,这也是程序猿优化代码迈出的第一步.

FileRequest源码

/*
 * Copyright (c) 2014,
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.kymjs.rxvolley.client;

import android.text.TextUtils;

import com.kymjs.rxvolley.http.HttpHeaderParser;
import com.kymjs.rxvolley.http.NetworkResponse;
import com.kymjs.rxvolley.http.Request;
import com.kymjs.rxvolley.http.Response;
import com.kymjs.rxvolley.http.URLHttpResponse;
import com.kymjs.rxvolley.http.VolleyError;
import com.kymjs.rxvolley.rx.Result;
import com.kymjs.rxvolley.toolbox.HttpParamsEntry;
import com.kymjs.rxvolley.toolbox.Loger;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.zip.GZIPInputStream;

/**
 * 请求文件方法类
 *
 * @author kymjs (http://www.kymjs.com/) .
 */
public class FileRequest extends Request<byte[]> {
    private final File mStoreFile;
    private final File mTemporaryFile; // 临时文件

    private ArrayList<HttpParamsEntry> mHeaders = new ArrayList<>();

    public FileRequest(String storeFilePath, RequestConfig config, HttpCallback callback) {
        super(config, callback);
        mStoreFile = new File(storeFilePath);
        File folder = mStoreFile.getParentFile();

        if (folder != null && folder.mkdirs()) {
            if (!mStoreFile.exists()) {
                try {
                    mStoreFile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        mTemporaryFile = new File(storeFilePath + ".tmp");
    }

    public File getStoreFile() {
        return mStoreFile;
    }

    public File getTemporaryFile() {
        return mTemporaryFile;
    }

    @Override
    public String getCacheKey() {
        return "";
    }

    @Override
    public boolean shouldCache() {
        return false;
    }

    @Override
    public Response<byte[]> parseNetworkResponse(NetworkResponse response) {
        String errorMessage = null;
        if (!isCanceled()) {
            if (mTemporaryFile.canRead() && mTemporaryFile.length() > 0) {
                if (mTemporaryFile.renameTo(mStoreFile)) {
                    return Response.success(response.data, response.headers,
                            HttpHeaderParser.parseCacheHeaders(getConfig().mUseServerControl,
                                    getConfig().mCacheTime, response));
                } else {
                    errorMessage = "Can't rename the download temporary file!";
                }
            } else {
                errorMessage = "Download temporary file was invalid!";
            }
        }
        if (errorMessage == null) {
            errorMessage = "Request was Canceled!";
        }
        return Response.error(new VolleyError(errorMessage));
    }

    @Override
    public ArrayList<HttpParamsEntry> getHeaders() {
        mHeaders.add(new HttpParamsEntry("Range", "bytes=" + mTemporaryFile.length() + "-"));
        mHeaders.add(new HttpParamsEntry("Accept-Encoding", "identity"));
        return mHeaders;
    }

    public ArrayList<HttpParamsEntry> putHeader(String k, String v) {
        mHeaders.add(new HttpParamsEntry(k, v));
        return mHeaders;
    }

    public static boolean isSupportRange(URLHttpResponse response) {
        if (TextUtils.equals(getHeader(response, "Accept-Ranges"), "bytes")) {
            return true;
        }
        String value = getHeader(response, "Content-Range");
        return value != null && value.startsWith("bytes");
    }

    public static String getHeader(URLHttpResponse response, String key) {
        return response.getHeaders().get(key);
    }

    public static boolean isGzipContent(URLHttpResponse response) {
        return TextUtils.equals(getHeader(response, "Content-Encoding"), "gzip");
    }

    public byte[] handleResponse(URLHttpResponse response) throws IOException {
        long fileSize = response.getContentLength();
        if (fileSize <= 0) {
            Loger.debug("Response doesn't present Content-Length!");
        }

        long downloadedSize = mTemporaryFile.length();
        boolean isSupportRange = isSupportRange(response);
        if (isSupportRange) {
            fileSize += downloadedSize;

            String realRangeValue = response.getHeaders().get("Content-Range");
            if (!TextUtils.isEmpty(realRangeValue)) {
                String assumeRangeValue = "bytes " + downloadedSize + "-" + (fileSize - 1);
                if (TextUtils.indexOf(realRangeValue, assumeRangeValue) == -1) {
                    Loger.debug("The Content-Range Header is invalid Assume["
                            + assumeRangeValue + "] vs Real["
                            + realRangeValue + "], "
                            + "please remove the temporary file ["
                            + mTemporaryFile + "].");
                }
            }
        }

        if (fileSize > 0 && mStoreFile.length() == fileSize) {
            mStoreFile.renameTo(mTemporaryFile);
            if (mProgressListener != null)
                mRequestQueue.getDelivery().postProgress(mProgressListener,
                        fileSize, fileSize);
            return null;
        }

        RandomAccessFile tmpFileRaf = new RandomAccessFile(mTemporaryFile, "rw");
        if (isSupportRange) {
            tmpFileRaf.seek(downloadedSize);
        } else {
            tmpFileRaf.setLength(0);
            downloadedSize = 0;
        }

        InputStream in = response.getContentStream();
        try {
            if (isGzipContent(response) && !(in instanceof GZIPInputStream)) {
                in = new GZIPInputStream(in);
            }
            byte[] buffer = new byte[6 * 1024]; // 6K buffer
            int offset;

            while ((offset = in.read(buffer)) != -1) {
                tmpFileRaf.write(buffer, 0, offset);
                downloadedSize += offset;
                //下载进度回调
                if (mProgressListener != null)
                    mRequestQueue.getDelivery().postProgress(mProgressListener,
                            downloadedSize, fileSize);
                if (isCanceled()) {
                    break;
                }
            }
        } finally {
            if (in != null) {
                in.close();
            }
            try {
                response.getContentStream().close();
            } catch (Exception e) {
                Loger.debug("Error occured when calling consumingContent");
            }
            tmpFileRaf.close();
        }
        return null;
    }

    @Override
    public Priority getPriority() {
        return Priority.LOW;
    }

    @Override
    protected void deliverResponse(ArrayList<HttpParamsEntry> headers, byte[] response) {
        HashMap<String, String> map = new HashMap<>(headers.size());
        for (HttpParamsEntry entry : headers) {
            map.put(entry.k, entry.v);
        }
        if (response == null) response = new byte[0];
        if (mCallback != null) {
            mCallback.onSuccess(map, response);
        }
        getConfig().mSubject.onNext(new Result(getUrl(), response, map));
    }
}

FormRequest源码

/*
 * Copyright (c) 2014, 张涛.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.kymjs.rxvolley.client;


import com.kymjs.rxvolley.RxVolley;
import com.kymjs.rxvolley.http.HttpHeaderParser;
import com.kymjs.rxvolley.http.NetworkResponse;
import com.kymjs.rxvolley.http.Request;
import com.kymjs.rxvolley.http.Response;
import com.kymjs.rxvolley.rx.Result;
import com.kymjs.rxvolley.toolbox.HttpParamsEntry;
import com.kymjs.rxvolley.toolbox.Loger;

import java.io.ByteArrayOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * Form表单形式的Http请求
 *
 * @author kymjs(http://www.kymjs.com)
 */
public class FormRequest extends Request<byte[]> {

    private final HttpParams mParams;

    public FormRequest(RequestConfig config, HttpParams params, HttpCallback callback) {
        super(config, callback);
        if (params == null) {
            params = new HttpParams();
        }
        this.mParams = params;
    }

    @Override
    public String getCacheKey() {
        if (getMethod() == RxVolley.Method.POST) {
            return getUrl() + mParams.getUrlParams();
        } else {
            return getUrl();
        }
    }

    @Override
    public String getBodyContentType() {
        if (mParams.getContentType() != null) {
            return mParams.getContentType();
        } else {
            return super.getBodyContentType();
        }
    }

    @Override
    public ArrayList<HttpParamsEntry> getHeaders() {
        return mParams.getHeaders();
    }

    @Override
    public byte[] getBody() {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            if (mProgressListener != null) {
                mParams.writeTo(new CountingOutputStream(bos, mParams.getContentLength(),
                        mProgressListener));
            } else {
                mParams.writeTo(bos);
            }
        } catch (IOException e) {
            Loger.debug("FormRequest#getBody()--->IOException writing to ByteArrayOutputStream");
        }
        return bos.toByteArray();
    }

    @Override
    public Response<byte[]> parseNetworkResponse(NetworkResponse response) {
        return Response.success(response.data, response.headers,
                HttpHeaderParser.parseCacheHeaders(getUseServerControl(), getCacheTime(),
                        response));
    }

    @Override
    protected void deliverResponse(ArrayList<HttpParamsEntry> headers, final byte[] response) {
        final HashMap<String, String> map = new HashMap<>(headers.size());
        for (HttpParamsEntry entry : headers) {
            map.put(entry.k, entry.v);
        }
        if (mCallback != null) {
            mCallback.onSuccess(map, response);
        }
        getConfig().mSubject.onNext(new Result(getUrl(), response, map));
    }

    @Override
    public Priority getPriority() {
        return Priority.IMMEDIATE;
    }

    public static class CountingOutputStream extends FilterOutputStream {
        private final ProgressListener progListener;
        private long transferred;
        private long fileLength;

        public CountingOutputStream(final OutputStream out, long fileLength,
                                    final ProgressListener listener) {
            super(out);
            this.fileLength = fileLength;
            this.progListener = listener;
            this.transferred = 0;
        }

        public void write(int b) throws IOException {
            out.write(b);
            if (progListener != null) {
                this.transferred++;
                if ((transferred % 20 == 0) && (transferred <= fileLength)) {
                    RxVolley.getRequestQueue().getDelivery().postProgress(this.progListener,
                            this.transferred, fileLength);
                }
            }
        }
    }
}

JsonRequest源码

/*
 * Copyright (c) 2014, 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.kymjs.rxvolley.client;


import com.kymjs.rxvolley.RxVolley;
import com.kymjs.rxvolley.http.HttpHeaderParser;
import com.kymjs.rxvolley.http.NetworkResponse;
import com.kymjs.rxvolley.http.Request;
import com.kymjs.rxvolley.http.Response;
import com.kymjs.rxvolley.rx.Result;
import com.kymjs.rxvolley.toolbox.HttpParamsEntry;
import com.kymjs.rxvolley.toolbox.Loger;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * 用来发起application/json格式的请求的,我们平时所使用的是form表单提交的参数,而使用JsonRequest提交的是json参数。
 */
public class JsonRequest extends Request<byte[]> {

    private final String mRequestBody;
    private final HttpParams mParams;

    public JsonRequest(RequestConfig config, HttpParams params, HttpCallback callback) {
        super(config, callback);
        mRequestBody = params.getJsonParams();
        mParams = params;
    }

    @Override
    public ArrayList<HttpParamsEntry> getHeaders() {
        return mParams.getHeaders();
    }

    @Override
    protected void deliverResponse(ArrayList<HttpParamsEntry> headers, byte[] response) {
        HashMap<String, String> map = new HashMap<>(headers.size());
        for (HttpParamsEntry entry : headers) {
            map.put(entry.k, entry.v);
        }
        if (mCallback != null) {
            mCallback.onSuccess(map, response);
        }
        getConfig().mSubject.onNext(new Result(getUrl(), response, map));
    }

    @Override
    public Response<byte[]> parseNetworkResponse(NetworkResponse response) {
        return Response.success(response.data, response.headers,
                HttpHeaderParser.parseCacheHeaders(getUseServerControl(), getCacheTime(),
                        response));
    }

    @Override
    public String getBodyContentType() {
        return String.format("application/json; charset=%s", getConfig().mEncoding);
    }

    @Override
    public String getCacheKey() {
        if (getMethod() == RxVolley.Method.POST) {
            return getUrl() + mParams.getJsonParams();
        } else {
            return getUrl();
        }
    }

    @Override
    public byte[] getBody() {
        try {
            return mRequestBody == null ? null : mRequestBody.getBytes(getConfig().mEncoding);
        } catch (UnsupportedEncodingException uee) {
            Loger.debug(String.format("Unsupported Encoding while trying to get the bytes of %s" +
                    " using %s", mRequestBody, getConfig().mEncoding));
            return null;
        }
    }

    @Override
    public Priority getPriority() {
        return Priority.IMMEDIATE;
    }
}

二 开闭原则

开闭原则(Open Close Principle),缩写OCP,他是Java世界里最基础的设计原则,它知道我们如何建立一个稳定的,灵活的系统.
概述:软件中的对象(类,模块,方法等)应该对于扩展是开放的,但是,对于修改是封闭的.在软件的生命周期内,因为变化,升级和维护等原因需要对软件原有代码进行修改时,可能会讲错误引入原本已经经过测试的老版本代码,破坏原有的系统.因此,当软件需要变化时,我们应该尽量通过扩展方式来实现变化,而不是修改已有的代码来实现.当然,在我们实际开发中,只通过继承的方式来升级,维护原有系统知识一个理想化的愿景,因此,在实际开发中,修改原有代码,拓展代码往往都是同时存在的

安卓源码分析截图:Android系统的上下文对象,即在Context中,为我们开发者封装了一个这个"语境".博文拿开发项目为例,点击一个基类,鼠标放在AppCompatActivity上,查看类继承关系(快捷键:Ctrl + H ),即可看到下图这个体系,请读者再结合上面概念细细回味
在这里插入图片描述

三 里氏替换原则

里氏替换原则(Liskov Substitution Principle),缩写LSP
概述:所有引用基类的地方必须能透明地使用个其子类的对象.(老爸能玩孩子的笔记本打魔兽).面向对象语言的三大特点是继承,封装,多态.里氏替换原则就是依赖继承.多态这两大特性.

历史替换元核心原理是抽象,抽象又依赖于继承这个特性,
继承优点:
1,代码重用,减少创建类的成本,每个子类都拥有父类的方法和属性
2,子类和父类基本相似,但又与父类有所区别
3,提高代码的可拓展性
继承缺点;
1,继承是侵入性,只要继承就必须拥有父类的所有方法和属性
2,可能造成子类代码冗余,灵活性降低,因为子类必须拥有父类的属性和方法

在这里插入图片描述

四 依赖倒置原则

依赖导致原则(Dependence Inversion Principle),缩写DIP
概述:依赖导致原则指代了一种特定的解耦形式,使得高层次的模块不依赖低层次的模块的实现细节的目的,依赖模块被颠倒了

1,高层模块不应该依赖低层模块,两者都应该依赖起抽象
2,抽象不应该依赖细节
3,细节应该依赖抽象

猜你喜欢

转载自blog.csdn.net/qXing123456789/article/details/83275587