Java如何设计一个类

1. 类和成员最小化可访问性

  • 问题

    要区分设计良好的模块和设计不好的模块,最重要的因素在于,这个模块对于外部其他模块而言,是否隐藏其内部数据和其他细节。设计良好的模块会隐藏所有的实现细节,把它的API与它的实现清晰的隔离起来,模块之间只通过它们的API进行通信,那么,在设计类和成员时有怎样的设计原则?

  • 解决

    设计类和成员有这样几个基本原则:

    1. 尽可能使每个类或者成员不被外界访问,应该使用与你正在编写的软件的对应功能相一致的、尽可能最小的访问级别;对于成员(域、方法、嵌套类或者嵌套接口)有四种访问级别:1. private--在该类中私有访问;2. 默认级别--包级访问;3. protected访问级别--该类的子类或者包类所有类均可访问到;4.public--在任何地方均可访问到;
    2. 如果类中覆盖了父类中的方法,那么子类中的访问级别不得低于父类中的访问级别,这样就可以保证在任何使用到父类实例的地方可以继续使用子类。如果一个类实现了某接口,那么在类中所有的接口的方法都必须是public的;
    3. 实例域决不能是公有的,如何非final实例域指向了可变对象,并且该实例域为public的话,那么包含该实例域的类就是线程不安全的;
  • 总结

    总之,在设计类和成员时,应该尽可能的降低可访问性,除了公有静态final域的特殊情形之外,公有类都不应该包含公有域,并且要确保公有的静态final域所引用的对象是不可变的。

2.使用访问方法

  • 问题

    有这样一个反例:

    class Point {
        public double x;
        public double y;
    }

    如上这样的类绝不应该声名为public,因为一旦声名为了public,该类中所有的数据就全部暴露出来,并且无法改变它的数据表示法,也无法强加任何约束条件,当被访问的时候,无法采取任何辅助措施,这么多问题,归结原因就是因为如果类声明不当,那么可能会将整个数据域全部暴露给客户端。虽然,对于可变类来说,应该用包含私有域和仅有设置方法的类代替:

    class Point {
        private double x;
        private double y;
    
        public Point(double x, double y) {
            this.x = x;
            this.y = y;
        }
    
        public double getX() { return x; }
        public double getY() { return y; }
    
        public void setX(double x) { this.x = x; }
        public void setY(double y) { this.y = y; }
    }

    那么,对类中的数据域的访问级别应该如何设计?

  • 解决

    1. 如果类的数据域可在它所在的包外部进行访问,就提供访问方法,这样可以保留该类内部表示的灵活性。如果公有类暴露了它的数据域,要想将来想改变公有类的内部数据接口,那是不太可能的事情了,因为使用公有类的数据域已经遍布整个系统中了;
    2. 对于公有类有一个约定,公有类永远都不应该暴露可变的域
  • 结论

    公有类永远都不应该暴露可变的域,有时候会需要用包级私有的或者私有的嵌套类来暴露域,无论这个类的域是可变的还是不可变的。

3.最小化可变性

  • 问题

    不可变类是其实例不能被修改的类,没有实例中所包含的数据域,在实例被创建的时候被初始化,且在实例的生命周期中不能被修改。JAVA中有许多不可变类,如String,值的基本包装类型,BigInteger和BigDecimal等,不可变类是线程安全的。不可变有很多优点,那么设计不可变类的原则有哪些?

  • 解决

    1. 设计不可变类有以下几条规则:

      • 不要提供任何修改实例数据域的setter方法
      • 保证类不会被扩展:防止子类恶意修改实例对象,应该禁止类被子类扩展,可以将其定义为final;或者让类所有的构造器都变成私有的或者包级私有的,并添加公有的静态工厂来代替公有的构造器;
      • 所有的域都是final的;
      • 所有的域都成为私有的,这样可以防止客户端获得访问被域引用的可变对象的权限,并防止客户端修改这些对象;
      • 确保对于任何可变组件的互斥性访问:如果类具有指向可变对象的域,则必须确保客户端无法获得指向这些对象的引用;
    2. 示例

      例如,String不可变类的具体实现为:

      public final class String
          implements java.io.Serializable, Comparable<String>, CharSequence
      {
          /** The value is used for character storage. */
          private final char value[];
          /** The offset is the first index of the storage that is used. */
          private final int offset;
          /** The count is the number of characters in the String. */
          private
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值