Effective Java:类和接口的设计

来源:互联网 发布:全职高手烽火知韩txt 编辑:程序博客网 时间:2024/05/16 09:19

13 使类和成员的可访问性最小化。

  • 实例域决不能是公有的。如果域是非final的,或者是一个指向可变对象的final引用,那么一旦使用这个于成为公有的,就放弃了对存储在这个于中的值进行限制的能力。

14 在公有类中使用访问方法而非公有域

  • 没有getter和setter,将来要修改的时候并不方便。
  • 如果类是包级私有的,或者是私有的嵌套类,那么暴露数据域并没有什么关系。

15 使可变性最小化

不可变类是实例不能被修改的类。每个实例中包含的 所有信息都必须在创建该实例的时候就提供,并在整个对象的生命周期内固定不变。如String。
* 不提供任何修改对象属性的方法。
* 保证类不会被拓展
* 使所有的域都是final的。
* 确保对于任何可变组件的互斥访问

如果类指向可变对象的于,则必须确保该类的客户端无法获得指向这些的对象的引用。并且,不要用客户端提供的对象引用来初始化这样的域,不要从任何访问方法来返回该对象引用(如:用于计算的类,返回一个新的类而不是自身,都是确保自身是一个不可被改变的类)。

不可变对象本质是线程安全的,它们不要求同步,单多个线程并发访问这样的对象的时候,它们不会遭到破坏。所以,不可变对象可以被自由的分享,这产生的结果是,不可变对象永远也不需要进行保护性拷贝。

不可变对象的缺点:每个不同的值,都需要一个单独的对象

复合优先于继承

继承是实现代码重用的有利手段,确非最佳。包内的继承是安全的,因为子类和超类的实现都处在同一个程序员的控制之下。对于普通的具体类进行跨越包的边界的继承,则是非常危险的。

危险性:继承打破了封装性。子类依赖于超类的特定功能实现的细节。超类的实现可能会随着版本的发行有所变化,从而破坏了子类。

17 要么为继承设计,并提供文档,要么就禁止继承。

提供的文档,要说明做了什么(这个更重要),而非怎么实现。

  • 为了允许继承, 类必须遵守其他一些约束。构造器决不能调用可被覆盖的方法,无论是直接调用或者是简介调用。

超类的构造器在子类的构造器之前运行,所以,子类中国覆盖版本的方法将会在子类的 构造器运行之前就先被调用。如果覆盖版本的方法依赖于子类构造器所之行的任何初始化工作,该方法将不会如预期般执行。

  • 为了继承设计类的时候,需要关注Cloneable和Serializable的实现。

如果实现Cloneable或者Serializable接口,需要意识到,clone和readObject都不可以调用可覆盖的方法,对于readObject方法覆盖版本的方法将在子类的状态被反序列化之前运行,对于clone方法,覆盖版本的方法则是在子类的clone方法有机会修正被克隆对新疆的状态之前被运行。

18:接口优于抽象类

  • 现有的类可以很容易被更新,以实现新的接口。
  • 接口是定义mixin的理想选择
  • 接口允许构造非参差接口的类型框架。

对于导出的每个重要接口都提供一个抽象的骨架实现类,把接口和抽象类的优点结合起来。接口仍然是定义类型,骨架实现类接管了所有接口实现的相关工作(在JDK8后,接口允许实现默认方法)。骨架的实现,它们为抽象类提供了实现上的帮助,又不强加“抽象类被用作类型定义时”所特有的严格限制。

接口只用于定义类型

常量接口模式是对接口的不良使用。

21 用函数对象表示策略

Java没有提供函数指针,对于用函数来实现的策略类方法(如Comparator<>),目前Java8已经提供了方法引用,方法也是一种对象。对于8以前的Java版本,可以使用一个接口完成。

public interface Comparator<T>{    public int compare(T t1, T t2);}//这个时候放进去一个就可以了Arrays.sort(stringArray, Comparator<T>);//或者匿名类Arrays.sort(stringArray, Comparator<String>{    public int compare(String str1, String str2){        ....    }    })

具体的策略类往往使用匿名类来声明。注意,以匿名类的方式使用时,将会在每次调用的时候创建一个行动实例,如果它被重复执行,可以考虑将函数对象存储到一个私有的静态final域里面.(类似于Comparator内置在Arrays里面),对于宿主类,可以采用策略模式,将比较的接口对象公开,可以从外面设置。(策略模式的用法)

22 嵌套类优先考虑静态成员类

嵌套类是指在类内部定义的类。它使用的目的是为它的外围类提供服务。如果嵌套类可能被用于其它环境当中,那么它应该被定义为顶层类。

嵌套类主要分为以下4种。

  • 静态成员类。
  • 非静态成员类、
  • 匿名类
  • 局部类

静态成员类和非静态成员类

语法上:静态成员类在定义的时候有static修饰。

静态成员类

其可以访问外围类的私有成员。不需要外围类就可以建立。

非静态成员类

可以访问外围类成员。每一个非静态成员类的实例都隐含的和外围类的一个实例相关联。非静态成员类的内部,可以使用外围类的方法,或者利用修饰过的this构造获得外围实例的引用。在没有外围存在的情况下,要想创建非静态成员类的实例是不可能的。

当非静态成员类实例建立的时候,和外围实例的关系也建立起来了,并且不能被修改,这种关联关系需要消耗非静态成员类实例的空间,并且增加了构造的时间。同时,由于这种关系的存在,当非静态成员类存在的时候,外围类即使没有显示的被引用,但是由于有这种隐式的关联关系,外围类实例不能被垃圾回收。

匿名类

不能被实例化,常用于做函数对象。

原创粉丝点击