编写稳定、灵活的程序——开闭原则

来源:互联网 发布:网络电视机顶功能 编辑:程序博客网 时间:2024/05/16 04:04

什么是开闭原则

1988年Bertrand Meyer(勃兰特·梅耶)出版了《面向对象软件构造》一书中提出了开闭原则。

开闭原则的英文全程是Open Close Principle,缩写是OCP,其定义如下:

一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。

它是Java世界里最基础的设计原则,这一原则指导我们在设计、编写程序的时候应该“尽量”对扩展开放、对修改关闭。

因为在软件的声明周期当中会随着时间的推移增加或更改很多的地方,这时我们可能需要更改原本已经通过测试的代码,这就可能会把原本已经没有问题的代码改出问题,使得开发人员和测试人员都需要花费更多时间在上面,增加了维护成本。

开闭原则就是为了解决上述问题而被提出的,但这只是一个愿望,实际情况并不能完全的符合这一原则,我们只能尽可能的去遵循这以原则,遵循开闭原则的一个很明显的优点就是使得我们的程序在维护的过程中更加稳定、更加灵活。

说了这么多,我们来看一下具体的代码来体会一下开闭原则。

Android源码中的开闭原则

ListView相信大家经常用吧,ListView提供一个setAdapter(ListAdapter adapter)方法,这个方法为ListView绑定了一个数据源,ListView通过一系列处理将这个数据源以列表的形式展示出来。那么我们看看这个ListAdapter的源码

public interface ListAdapter extends Adapter {    ...}

我们可以看到这个ListAdapter是一个接口,那么我回想一下我们平时常用的几种Adapter,有SimpleAdapter、BaseAdapter等,其源码如下:

public class SimpleAdapter extends BaseAdapter implements Filterable, ThemedSpinnerAdapter {    ...}public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {    ...}

通过上面的源码我们可以看到SimpleAdapter 继承了BaseAdapter,而BaseAdapter又实现了ListAdapter,所以我们在平时调用ListView的setAdapter方法时即可传一个SimpleAdapter的实例,也可以传一个BaseAdapter的实例当做参数,就是因为这两个类都是ListAdapter的子类,这也是Java多态的特征。因为这里的setAdapter方法是面对ListAdapter接口编程的,所以对于使用者更加灵活,假如我们第一传了一个SimpleAdapter的实例作为参数,但是后期维护中发现需要更改为BaseAdapter的实例作为参数,这样我们只需要写一个具体的BaseAdapter实现类,然后将BaseAdapter的实现类的实例传给setAdapter即可。在这个过程中相对Adapter的角度来说我们对Adapter进行了扩展,但是我们并未修改原来的SimpleAdapter的代码,从某种角度来说这里Android对于Adapter的设计就符合了开闭原则。

说了这么多相信大家对开闭原则有了新的认识,开闭原则提倡我们将系统进行抽象,将系统抽象出对应的接口或抽象类,在开发的过程中都面向接口或抽象类来编程,这样会使得我们的程序更灵活,维护的过程中也会相对比较稳定。

最后我们在通过一个小例子来看看我们日常代码中那些地方体现出来开闭原则:

被你忽略的开闭原则

我们看看下面一个简单的方法:

public String getString(ArrayList<String> list) {        if(list == null || list.size() <= 0)            return "";        StringBuilder temp = new StringBuilder();        for(String str : list) {            temp.append(str + "-");        }        return temp.toString();}

为了说明日常开发中我们运用的开闭原则,我编写了一个小例子,上面的方法接收一个ArrayList作为参数,然后遍历这个ArrayList,将其中的字符串进行拼接,返回。看起来很简单,但是这个ArrayList参数却很可能给我们带来一些小麻烦,加入调用这个方法的时候我们只能提供一个LinkedList,而非ArrayList,那么我们就可能要修改这个方法的实现为下面的形式:

public String getString(LinkedList<String> list) {        if(list == null || list.size() <= 0)            return "";        StringBuilder temp = new StringBuilder();        for(String str : list) {            temp.append(str + "-");        }        return temp.toString();}

有同学会认为修改成上面的形式也很简答、或者在起初我们就提供两个方法一个为参数是ArrayList,一个为参数是LinkedList不就可以了么。难道就不能只提供一个稳定、灵活的方法来处理这些参数么?答案是有。我们稍作改动如下:

public String getString(List<String> list) {        if(list == null || list.size() <= 0)            return "";        StringBuilder temp = new StringBuilder();        for(String str : list) {            temp.append(str + "-");        }        return temp.toString();}

我们将参数修改为List,这样就可以适应参数为ArrayList、LinkedList等形式的参数了,为什么呢?我们看看List的继承结构。如下图所示:

这里写图片描述

这里我们可以看到ArrayList和LinkedList都是List的实现类,所以说上面的方法可以接受所有List的实现类的实例作为参数,说了这么多大家可能感觉这个例子太简单了。但这其对于这个方法的封装确实体现开闭原则。只有在这些细节上我们认真分析、认真考虑、准许这些原则才能写出更好的程序。

当你对设计原则或者设计模式有新的认识之后你会对编程更加敢兴趣,因为当你运用某种原则后者模式编写出来的一段程序之后,你会非常有成就感、你会真正的体会到,编程是一门艺术。

文中提到的一些例子只是为了帮助大家更好的理解开闭原则,如有不当的地方欢迎大家留言、拍砖。

1 0
原创粉丝点击