第5章 只公开你要公开的内容

第五章  只公开你要公开的内容

-----------------------------------------

 【重点】 对于每一个设计模式的数据,都会对API设计有一个建议,那就是“API公开的内容越少越好”。  

  有一些API总是会保持着利他主义精神,在API中提供了大量的辅助类和工具,认为只要有人用得上这些功能,就认为有必要公开的,所以将所有的类变成外部可访问的public级别,还有很多类中带有要么是public,要么是protected声明的成员。提供的对外的功能越多,那么为保持向后兼容性所做的工作也就越多。留给具体实现的功能也就最小,未来改进的可能性也就最小。

  决定哪些功能应该为API的一部分,这一点却是没有标准化,但从作者写道NetBeans团队中中确立这一个标准就是用例化,成员们应该基于用例的方式来解决该问题。只有有一个有效的用例或者多个用例来证明一个方法或者一个类应该成为API的一部分。

  经验告诉我们,对于API设计者来说,起水平越差,他所编写的API越公开大量的内容。

  以下几点为API的设计技巧。

(1)方法优于字段

  对于类中的属性不要直接公开,而是提供方法进行公开,比较常用的就是提供get,set方法,以前本人也没有考虑过这么提供的好处,只知道学习编程的时候,类的三特性,那就封装,继承,抽象,封装中提及的一点,就是将所有的属性进行私有化,提供get,set方法,而这样提供的好处:应该提供方法可以在方法内部添加很多额外的处理机制,比如懒加载,同步访问或者一个特定的算法计算等。这也是java虚拟规范,优先使用方法而非直接访问字段。

  所以综上,对于static,final,枚举,String常量,还有一些不可变的对象以外,应该其余的字段应该通过get,set访问。

(2)工厂方法优于构造函数

  工厂方法则为开发人员带来了很高的灵活性,它通常是静态方法,这个工厂方法参数与构造函数的参数是一致。使用工厂方法的第一个优点在于工厂方法中返回的实例不一定是声明类型的实例,可以是它的子类实例,使用工厂方法可以体现面向对象语言中多态的特性,代码会显的更加简洁,另外,每次返回的对象不一定是必须要创建的,也可以将这些实例对象进行缓存下来。并重用他们,节省内存,第三个优势则在于同步的控制,在工厂方法中可以将创建对象前后的相应代码进行统一处理,构造函数对于这种情况就无能为力了。

  从jdk1.5引入泛型之后,工厂方法就多了一个优点,那就是工厂方法支持参数化的返回类型,但构造函数是做不到这一点的。

(3)让所有内容都不可更改

  通常情况下,如果不考虑子类,我们可以设计API的时候,将这个类修饰成final类型,不支持继承,要知道一旦API发布了以后,随之而来的大量无法预计的事情,其后果可能会比较危险。

  例如,有一个Hello类。可以有多种使用方法:

public class Hello {

    public void hello() {
        System.out.println("hello");
    }
}

//使用一
class Test1 {
    public static void main(String[] args) {
        Hello hello = new Hello();
        hello.hello();
    }
}

//使用二
class Test2 extends Hello {

    @Override
    public void hello() {
        System.out.println("hello2");
    }
}

//使用三
class Test3 extends Hello {

    @Override
    public void hello() {
        super.hello();
        System.out.println("hello2");
    }
}

  非常简单的方法就是,将Hello,通过final修饰,一切问题就迎刃而解了。

  为了考虑对该类的改造,最好还是不要让该类无法被继承,减少外部的使用方式。

  除了通过final修饰,还可以通过工厂方法,不公开构造函数,也可以避免该类被继承(这种方式是被推荐的)

(4)避免滥用setter方法

  在作者开发NetBeans后,作者得到一个宝贵的经验:如无必要,绝不要在正式的API中声明setter方法,所谓“正式的API”则是指提供给外部开发人员来实现的接口。类似spring的注入功能就很有必要提供setter功能,否则注入就会失败。

(5)尽可能通过友元的方式来公开功能

  说到如何避免在一个API中公开太多的内容,还有一个比较有效的方式就是通过友元的方式来访问API的功能的,比如说,创建一个对象或者调用一个方法,这些功能都只有满足友元条件的代码才能访问。

  所谓的友元也就是默认的package包可以访问的方式。只允许同一个包类进行访问,比如说构造函数,字段以及方法都声明为package,这种友元的访问方式可以避免外部类对包内功能的调用。

  有时候需要在更大的范围使用一些功能,此时必须对一些友元访问的内容进行扩展,例如,定义了两个包,一个包用来定义纯粹对外的API,而另外一个包则防止具体实现的内容。

(6)赋予对象创建者更多权利

  尽管java语言中,对象的创建者没有任何特殊的访问级别,但通过一些技巧仍然可以在API中实现此需求,解决方案很多,从最简单,最难看的到最复杂的,最优雅的,一应具有,而在作者看来,最好的处理方式则是利用两个类,一个类为对象的创建者提供高级权限,而另一个提供公开的API,供任何人调用。

(7)避免暴露深层次继承

  有些朋友认为,面向对象之所以优秀,是因为他的复用,但这种出色的表现并不意味着它功能复用方面的提升,因为代码复用的主要问题在于交流而非其他方面。

  所能给出的建议:避免深层次继承,定义程序的接口,并让用户来实现这些接口。

  所以一旦发现继承体系超过两层时,一定要打住,并多多思考一下,要想清楚:我到底是在设计API还是在复用代码。

 

~~~~~~

由于篇幅有限,感兴趣的朋友可以购买《软件框架设计的艺术》来详细了解和深入。  

 

  

 

 

   

posted @ 2016-12-02 17:08  强仔Johnny  阅读(144)  评论(0编辑  收藏  举报