公共技术点之面向对象六大原则

概述

在工作初期,我们可能会经常会有这样的感觉,自己的代码接口设计混乱、代码耦合较为严重、一个类的代码过多等等,自己回头看的时候都觉得汗颜。再看那些知名的开源库,它们大多有着整洁的代码、清晰简单的接口、职责单一的类,这个时候我们通常会捶胸顿足而感叹:什么时候老夫才能写出这样的代码!

在做开发的这些年中,我渐渐的感觉到,其实国内的一些初、中级工程师写的东西不规范或者说不够清晰的原因是缺乏一些指导原则。他们手中挥舞着面向对象的大旗,写出来的东西却充斥着面向过程的气味。也许是他们不知道有这些原则,也许是他们知道但是不能很好运用到实际代码中,亦或是他们没有在实战项目中体会到这些原则能够带来的优点,以至于他们对这些原则并没有足够的重视。

今天,我们就是以剖析优秀的Android网络框架Volley为例来学习这六大面向对象的基本原则,体会它们带来的强大能量。

在此之前,有一点需要大家知道,熟悉这些原则不会让你写出优秀的代码,只是为你的优秀代码之路铺上了一层栅栏,在这些原则的指导下你才能避免陷入一些常见的代码泥沼,从而让你专心写出优秀的东西。另外,我是个新人,以下只是我个人的观点。如果你觉得还行,可以顶个帖支持一下;如果你觉得它不行,,还请分享你的经验。

Volley相关资料单一职责原则 ( Single Responsibility Principle )简述

单一职责原则的英文名称是Single Responsibility Principle,简称是SRP,简单来说一个类只做一件事。这个设计原则备受争议却又及其重要的原则。只要你想和别人争执、怄气或者是吵架,这个原则是屡试不爽的。因为单一职责的划分界限并不是如马路上的行车道那么清晰,很多时候都是需要靠个人经验来界定。当然最大的问题就是对职责的定义,什么是类的职责,以及怎么划分类的职责。

试想一下,如果你遵守了这个原则,那么你的类就会划分得很细,每个类都有自己的职责。恩,这不就是高内聚、低耦合么! 当然,如何界定类的职责这需要你的个人经验了。

示例

在Volley中,我觉得很能够体现SRP原则的就是HttpStack这个类族了。HttpStack定义了一个执行网络请求的接口,代码如下 :

/** * An HTTP stack abstraction. */{/*** 执行Http请求,并且返回一个HttpResponse*/public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)throws IOException, AuthFailureError;}

可以看到,HttpStack只有一个函数,清晰明了,它的职责就是执行网络请求并且返回一个Response。它的职责很单一,这样在需要修改执行网络请求的相关代码时我们只需要修改实现HttpStack接口的类,而不会影响其它的类的代码。如果某个类的职责包含有执行网络请求、解析网络请求、进行gzip压缩、封装请求参数等等,那么在你修改某处代码时你就必须谨慎,以免修改的代码影响了其它的功能。但是当职责单一的时候,你修改的代码能够基本上不影响其它的功能。这就在一定程度上保证了代码的可维护性。注意,单一职责原则并不是说一个类只有一个函数,而是说这个类中的函数所做的工作必须要是高度相关的,也就是高内聚。HttpStack抽象了执行网络请求的具体过程,接口简单清晰,也便于扩展。

我们知道,Api 9以下使用HttpClient执行网络请求会好一些,api 9及其以上则建议使用HttpURLConnection。这就需要执行网络请求的具体实现能够可扩展、可替换,因此我们对于执行网络请求这个功能必须要抽象出来,HttpStack就是这个职责的抽象。

优点里氏替换原则 ( Liskov Substitution Principle)简述

面向对象的语言的三大特点是继承、封装、多态,里氏替换原则就是依赖于继承、多态这两大特性。里氏替换原则简单来说就是所有引用基类的地方必须能透明地使用其子类的对象。通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。

示例

还是以HttpStack为例,Volley定义了HttpStack来表示执行网络请求这个抽象概念。在执行网络请求时,我们只需要定义一个HttpStack对象,然后调用performRequest即可。至于HttpStack的具体实现由更高层的调用者给出。示例如下 :

public static RequestQueue newRequestQueue(Context context, HttpStack stack) {File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);String userAgent = “volley/0”;() {if (Build.VERSION.SDK_INT >= 9) {HurlStack();} else {HttpClientStack(AndroidHttpClient.newInstance(userAgent));}}// 2、将HttpStack对象传递给Network对象Network network = new BasicNetwork(stack);// 3、将network对象传递给网络请求队列RequestQueue RequestQueue(new DiskBasedCache(cacheDir), network);queue.start();return queue;}

BasicNetwork的代码如下:

/** * A network performing Volley requests over an {@link HttpStack}. */{HttpStack mHttpStack;protected final ByteArrayPool mPool;public BasicNetwork(HttpStack httpStack) {this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));}public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {mHttpStack = httpStack;mPool = pool;}}

上述代码中,BasicNetwork构造函数依赖的是HttpStack抽象接口,任何实现了HttpStack接口的类型都可以作为参数传递给BasicNetwork用以执行网络请求。这就是所谓的里氏替换原则,任何父类出现的地方子类都可以出现,这不就保证了可扩展性吗?! 此时,用手撑着你的小脑门作思考状… 任何实现HttpStack接口的类的对象都可以传递给BasicNetwork实现网络请求的功能,这样Volley执行网络请求的方法就有很多种可能性,而不是只有HttpClient和HttpURLConnection。

不敢接受失败的人,往往是那些追求完美的人,

公共技术点之面向对象六大原则

相关文章:

你感兴趣的文章:

标签云: