罗列一些编写类与接口时的建议或优化点

下面记录了一些关于类和接口的经典条目:

  • 区分一个组件设计得好不好,唯一重要的因素在于,它对于外部的其他组件而言,是否隐藏了其内部数据和其他实现细节。设计良好的组件会隐藏所有的实现细节,把 API 与 实现清晰地隔离开来。 然后,组件之间只通过 API 进行通信,一个模块不需要知道其他模块的内部工作情况。 这个概念被称为信息隐藏( info1mation hiding)或封装( encapsulation ), 是软件设计的基本原则之一。
  • 应该始终尽可能(合理)地降低程序元素的可访问性。 在仔细地设计了一个最小的公有 API 之后,应该防止把任何散乱的类、接口或者成员变成 API 的一部分。 除了公有静态 final 域的特殊情形之外(此时它们充当常量),公有类都不应该包含公有域,并且要确保公有静态 final 域所引用的对象都是不可变的。
  • 公有类永远都不应该暴露可变的域。虽然还是有问题,但是让公有类暴露不可变的域,其危害相对来说比较小。 但有时候会需要用包级私有的或者私有的嵌套类来暴露域,无论这个类是可变的还是不可变的。坚决不要为每个 get 方法编写一个相应的 set 方法。除非有很好的理由要让类成为可变的类,否则它就应该是不可变的。除非有令人信服的理由要使域变成是非 final 的,否则要使每个域都是 private final的。
  • 继承的功能非常强大,但是也存在诸多问题,因为它违背了封装原则。 只有当子类和超类之间确实存在子类型关系时,使用继承才是恰当的。 即使如此,如果子类和超类处在不同的包中,并且超类并不是为了继承而设计的,那么继承将会导致脆弱性 ( fragility )。为了避免这种脆弱性,可以用复合和转发机制来代替继承,尤其是当存在适当的接口可以实现包装类的时候。包装类不仅比子类更加健壮,而且功能也更加强大。
  • 专门为了继承而设计类是一件很辛苦的工作。你必须建立文档说明其所有的自用模式,并且一旦建立了文档,在这个类的整个生命周期中都必须遵守。 如果没有做到,子类就会依赖超类的实现细节,如果超类的实现发生了变化,它就有可能遭到破坏。 为了允许其他人能编写出高效的子类,还你必须导出一个或者多个受保护的方法。 除非知道真正需要子类,否则最好通过将类声明为 final,或者确保没有可访问的构造器来禁止类被继承。
  • 接口通常是定义允许多个实现的类型的最佳途径。 如果你导出了一个重要的接口,就应该坚决考虑同时提供骨架实现类。 而且,还应该尽可能地通过缺省方法在接口中提供骨架实现,以便接口的所有实现类都能使用。也就是说,对于接口的限制,通常也限制了骨架实现会采用的抽象类的形式。可以使用 “模板方法设计模式”,将抽象类和接口的优点结合起来,既不用担心接口缺省方法的缺陷(不能包含实例域或非公有的静态成员),也不用烦恼抽象类的不灵活性(无法更新现有的类来扩展新的抽象类,同时不能给抽象方法添加缺省实现)。

在 Java 8 中,给接口增加了缺省方法( default method)构造,目的就是允许给现有的接口添加方法。

  • 接口应该只被用来定义类型 , 它们不应该被用来导出常量。
  • 标签类很少有适用的时候。当你想要编写一个包含显式标签域的类时,应该考虑一下,这个标签是否可以取消,这个类是否可以用类层次来代替。当你遇到一个包含标签域的现有类时,就要考虑将它重构到一个层次结构中去。
  • 共有四种不同的嵌套类,每一种都有自己的用途。 如果一个嵌套类需要在单个方法之外仍然是可见的,或者它太长了,不适合放在方法内部,就应该使用成员类。 如果成员类的每个实例都需要一个指向其外围实例的引用,就要把成员类做成非静态的;否则,就做成静态的,它不需要任何指向外围实例的引用,往往用于辅助外围类的某个功能一起对外使用,比如枚举类、静态方法的单例模式。假设这个嵌套类属于一个方法的内部,如果你只需要在一个地方创建实例,并且已经有了一个预置的类型可以说明这个类的特征,就要把它做成匿名类 ;否则,就做成局部类。
  • 永远不要把多个顶级类或者接口放在一个源文件中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值