盒子
盒子
文章目录
  1. 前言
  2. 最小化类和成员的可访问性
    1. 信息隐藏 information hiding/封装 encapsulation:
    2. 信息隐藏的好处
    3. 规则
  3. 在公有类中使用访问方法而不是公有域
  4. 使可变性最小化
  5. 复合优先于继承(不包括接口继承)
    1. 复合 composition
  6. 要么为继承而设计,并提供文档说明,要么就禁止继承
  7. 接口优于抽象类
  8. 接口只用于定义类型
  9. 类层次优于标签类
  10. 用函数对象表示策略
  11. 优先考虑静态成员类

类与接口--《Effective Java》

前言

本文为阅读《Effective Java》第四章阅读笔记。


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

信息隐藏 information hiding/封装 encapsulation:

良好的模块隐藏所有的实现细节,把API与实现清晰地隔离开。模块之间只通过API进行通信,并不需要知道其他模块内部工作情况。

信息隐藏的好处

有效解除各模块之间的耦合关系,使其可以独立开发、测试、优化、使用、理解和修改,从而加快系统开发速度,也减轻了维护的负担,可以有效地调节性能。
信息隐藏提高了软件的可重用性。降低了构建大型系统的风险。

规则

尽可能使每个类或成员不被外界访问。
访问级别如下:

  • private – 只有在声明该成员的顶层类内部才可访问
  • package-private – 默认访问级别。声明该成员的包内部的任何类都可以访问该成员。
  • protected – 声明该成员的类的子类可访问,声明该成员的包内部的任何类也可访问该成员。
  • public – 任何地方都可访问。

实例域绝不能是公有的。除了公有静态final域的特殊情形之外,公有域都不应该包含公有域,并要确保公有静态final域引用的对象都是不可变的。


在公有类中使用访问方法而不是公有域

如果类可以在它所在的包的外部进行访问,就提供访问方法。
公有类永远不应该暴露可变的域。


使可变性最小化

为了使类成为不可变,要遵循以下规则:

  1. 不要提供任何会修改对象状态的方法
  2. 保证类不会被扩展
  3. 使所有的域都是final的
  4. 使所有的域都成为私有的。
  5. 确保对于任何可变组件的互斥访问。

不可变对象本质上是线程安全的,不要求同步。
不可变对象可以被自由地共享。

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


复合优先于继承(不包括接口继承)

继承的问题在于超类改变后,子类会出现相应的错误。
只有当子类是超类的子类型(“is-a”关系)时,才适合用继承。

复合 composition

在新的类中增加一个私有域,引用现有类的一个实例。
转发 forwarding – 新类中的每个实例方法都可以调用被包含的现有类实例中对应的方法并返回其结果。
转发方法 forwarding method – 新类中的方法

优势: 不依赖于现有类的实现细节。即使现有类增加了新方法也不会影响新的类。


要么为继承而设计,并提供文档说明,要么就禁止继承

为了允许继承,类的构造器绝不能调用可被覆盖的方法。因为超类的构造器在子类的构造器之前运行,所以子类中覆盖版本的方法会在子类构造器之前就先被调用。

对于那些并非为了安全地进行子类化而设计和编写文档的类,要禁止子类化。
要么把这个类声明为final,要么把所有构造器变为私有或包级私有,并增加一些公有的静态工厂来替代构造器。


接口优于抽象类

抽象类允许包含某些方法的实现,但接口不行。
为了实现由抽象类定义的类型,类必须成为抽象类的一个子类。Java只允许单继承。

接口允许构造非层次结构的类型框架。


接口只用于定义类型

常量接口模式是对接口的不良使用,将实现细节泄漏到该类的导出API中。

如果大量利用工具类导出的常量,可以利用静态导入机制,避免用类名来修饰常量名。

接口应该只被用来定义类型,不应该被用来导出常量。


类层次优于标签类

标签类 tagged class 过于冗长,容易出错,效率底下。
举例: Figure 类同时包含 CIRCLE,RECTANGLE 的各种属性和方法。
解决方案:
将标签类转换为类层次。例如 Figure类只需要area的方法,而其他的东西类似radius针对于圆形、length和width针对于矩形的放在各自子类中。

类层次的好处:
反映类型之间本质上的层次关系,有助于增强灵活性,并进行更好的编译时类型检查。


用函数对象表示策略

函数指针的主要用途就是实现策略模式。在JAVA中,要声明一个接口来表示该策略,并为每个具体策略声明一个实现了该接口的类。当一个具体策略只被使用一次时,通常使用匿名类来声明和实例化这个具体策略类。 当一个具体策略是设计用来重复使用的时候,它的类通常就要被实现为私有的静态成员类,并通过公有的静态final域被导出,其类型为该策略接口。


优先考虑静态成员类

嵌套类 – 被定义在另一个类的内部的类。
嵌套类有四种:

  1. 静态成员类 static member class
    可以访问外围类的所有成员,包括声明为私有的成员。
    静态成员类的声明中包含static
    如果声明成员类不要求访问外围实例,就要使用静态成员。

  2. 非静态成员类 nonstatic member class
    在其内部,可以调用外围实例的方法,或利用修饰过的this构造获得外围实例的引用。
    如果嵌套类的实例可以在它外围类的实例之外独立存在,这个嵌套类必须是静态成员类。
    在没有外围实例的情况下,要想创建非静态成员类的实例是不可能的。
    常见用法: 定义一个Adapter

  3. 匿名类 anouymous class
    常见用法: 动态地创建函数对象; 创建过程对象; 在静态工厂方法内部。
  4. 局部类 local class

如果嵌套类需要在单个方法之外仍可见或者太长了不适合放在方法内部,就应该使用成员类。如果成员类的每个实例都需要一个指向其外围实例的引用,就做成非静态;否则就做成静态的。
假设这个嵌套类属于一个方法的内部,如果只需要在一个地方创建实例,并且已经有了一个预置的类型可以说明这个类的特征,就做成匿名类,否则就做成局部类。

支持一下
扫一扫,支持小王子