Effective-java-第四章学习笔记

第四章: 类和接口

引言

这章主要讲了类和接口的设计原则,如何设计除更健壮,更灵活的类和接口.

正文

使类和成员的访问最小化以及在公有类中使用访问方法而非公有域

前面两条实质上讲的是一件事,就是不要暴露类的内部成员,如果是公有类(一般情况我们写的都是public的类)一定不能暴露内部的成员,而是使用gettersetter.
尽可能的降低内部成员的可访问性. 这么做的好处就是封装性比较强, 也灵活很多,如果将来想在类的成员上做限制,直接在getter或者setter上做改变就可以, 外部调用者完全感受不到变化.

如果编写一个不可变的类

  1. 不要提供任何会修改对象状态的方法–比如setter
  2. 保证类不会被扩展–使用final修饰符或者private的构造器.
  3. 将所有的域(类的成员)都设置成private final的.
  4. 确保任何可变组件的互斥访问–就是如果类的成员是一个对象引用, 则保证这个引用不会被外部获取到.

functional: 不改变当前实例, 而是创建一个返回一个新的实例的方法. 这种方法被称为functional. 这种方法的方法名都使用介词.

不可变对象的优点:

  1. 不可变对象是线程安全的, 不要求同步.
  2. 不可变对象可以自由的共享, 甚至可以共享他们的内部信息.
  3. 不可变对象可以为其他对象提供构件.
  4. 不可变对象提供了原子性.

不可变对象的缺点

每一个不同的值都需要一个对象, 如果创建不可变对象代价太高, 那么可能会导致程序性能下降. 一般不可变对象都提供一个对应的可变的配套类,比如StringStringBuilder.

组合(复合)优于继承

  1. 继承打破了封装性.子类依赖父类其中特定的功能细节,如果将来父类改变了,那么子类也会跟着发生相应的变化,往往这些变化不是子类自己能控制的. 除非父类是专门用来被继承的或者有很好的说明该如何继承该类, 否则最好使用组合.
  2. 如果A和B两者直接存在is-a的关系才应该使用继承, 在实现继承时候, 要反复的确定 B 在任何时候都是一个 A 类型. 如果不是, B 仅仅是使用了 A 的一个功能, 那么就应该使用组合模式.

要么设计继承并提供文档, 要么禁止继承

这条其实是对于上面那条的补充说明, 上一条说如果继承了一个不是用来被继承的类,是一件很危险的事情, 可能导致封装性被破坏, 在设计一个被继承的类时, 要有良好的说明

  1. 该类必须有说明可以被重写的方法的自用性–即类必须在文档中说明,在哪些情况下它会调用被重写的方法.
  2. 对于为了继承而设计的类, 必须在发布之前先编写子类对其进行测试.
  3. 构造器不可以调用可以被重写的方法.
  4. clonereadObject 方法也不能调用可以被重写方法.

接口优于抽象类

如果是对实现类的规范和约束则应该使用抽象类, 如果想实现多继承则应该使用接口. 接口的可扩展性要优于继承.

接口的使用

  1. 为后代设计接口.
  2. 接口只用于定义类型.
  3. 不要使用常量接口.

写在最后

整章对于在写代码设计类的层次接口非常有用, 但是由于使用spring框架, 很多事情spring都帮你做了, 这些设计原则用到的机会不是非常多, 导致里面有很多东西看了似懂非懂, 所以以后还是要离开spring框架单独做一些非web项目, 这样才能有较深的感悟.