Java面向对象设计最佳实践——内置类设计

从这篇文章开始进入实战阶段的设计阶段,本文介绍内置类设计的最佳实践。
回顾一下,类(Class)做为Java编程语言中的基本单元模块,提供了面向对象的四种基本性质: 抽象性、封装性、继承性和多态性
在面向对象设计原则中, 尽量偏好方法,而非字段(或属性) 。简单的说,方法更好的表达语义。所以,在方法实现过程当中,常常会遇到相似的情景,接口方法method1 调用其余方法来完成功能须要。无非有三种状况,利用本类的(静态或者实例的)方法,调用某个类的静态可访问的方法和某个实例可访问的实例方法。可是, 良好类设计是尽可能的隐藏实现细节,简单清晰地表达语义
客户端程序只关心输入和输出,没有必要去关心中间的细节。回到上述的三状况,尽量隐藏本类和他类的细节。若是本类和他类相互耦合,那么扩张性和易用性受到必定程度的影响。可是设计人员想让本类和他类相互知晓,或者范围限制(主要是指类之间的访问限制)尽量小,那么内置类是一个很好的办法。
笔者把内置类分为三类:类内置类(Nested Class)实例内置类(Inner Class)和布局内置类(Local Class) 。下面分别介绍这三种类的使用场景和设计方法。
类内置类(Nested Class) ,在内置类中使用得最多的一类。其做为类的一部分,随外层类(Enclosing Class)顺序地被加载。它的好处是,定义的类内置类仅此一次被建立并加载,可视外层类的类成员。那么使用场景不可贵出,对于实例成员不感冒,只关心类成员,而且减小没有必要重复类的建立和加载。在大多数实际状况中,这个模式已经足够了。举一个的JDK里面的例子,迭代Map的时候,键值对实体接口 java.util.Map.Entry<K, V> ,其定义在 java.util.Map<K, V> 接口中,天然其修饰符是 public static final
为了客户端程序可以利用 java.util.Map.Entry<K, V> JDK暴露了 它。通常来讲, private final static是通用的设计。外层类对其是彻底可视的,所以private 是没有问题的。至于final的修饰,要谈到笔者设计经验中的一个原则,尽可能使用final修饰可修饰的。其中有几个好处,好比线程安全、拒绝子类、标准化(在后面的设计文章中会详细说明)等。 在内置类设计中,不该该指望其余类继承这个类,更不要指望其余人会使用的内置类了 。又回到JDK,你们会发现 java.util.HashMap<K,V > 内部定义很多的类内置类。
使用下面代码实例补充说明上述:

/**
* OuterClass 是外层类,NestedClass 类内置类
* @author mercyblitz
*/

public class OuterClass {
       /**
       * private final static 是类内置类的通用设计技巧
       */

       private final static class NestedClass {
      }
}
代码 -1
若是 OuterClass类中有实例变量的话,显然 NestedClass 是不可见的,也是不适用的(由于它是类的一部分)。
这个时候,利用实例内置类能够解决这类问题。
示例代码以下:

/**
* OuterClass2 是外层类,InnerClass 实例内置类
*
* @author mercyblitz
*/

public class OuterClass2 {

         private String message;

         /**
         * 使用private final 是一种好习惯。:D
         */

         private final class InnerClass {
                 /**
                 * 输出OuterClass2消息
                 */

                 private void outputMessageFromOuterClass2() {
                         // 注意,this的命名空间
                        System.out.println(OuterClass2. this.message);
                }
        }
}
代码 -2
在“代码-2”中,InnerClass利用OuterClass2message字段做为输出。
可能有人会说,InnerClass这种实例内,为了获得这个类,不得不建立一个实例,太浪费资源了,为何不直接把OuterClass实例做为参数,直接传入到InnerClass的方法呢?
没错,能够那么作。不过单从访问外层类的实例变量而言,利用实例内置类是有点显得浪费。若是客户端利用了泛型编程的话,状况就会不一样。
总所周知, 泛型设计可以提升灵活性,但是也有不少限制。模版参数类型是跟随其寄主类的, 模板参数类型是不会写入class文件中的,这就是为何反射(Reflection)不能解析出类的模板参数类型。可是,模板参数类型在实例(对象)范围是可用的(或可视的) 。若是内置类中想要利用外层类的模板参数类型的话,那么实例内置类就有很大用处。
例子以下:

/**
* OuterClass3 是外层类,InnerClass 实例内置类
*
* @author mercyblitz
* @param <T>
*                        模板参数类型,实例内置类能够利用
*/

public class OuterClass3<T> {

         private T data;

         /**
         * 使用private final 是一种好习惯。:D
         */

         private final class InnerClass {
                 public void setData(T newData) {
                        OuterClass3. this.data = newData;
                         // DOES Other things
                }
        }
}
代码 -3
      
“代码-3”中的实例内置类利用外层类OuterClass3中的模板参数T,做为setData参数的类型。
看似类内置类和实例内置类已经足够使用了。考虑这么一个场景,一个方法利用了内置类来实现功能,这个方法中的变量须要被内置类来利用,一般能够把变量做为参数,传入内置类构造器或者其方法中,这也是一般的方法。不过利用 布局 内置类(Local Class) 更为方便,由于局部内置类是在块中(方法也是一种特殊的块)定义的,这样就很好的解决了上下文的参数传递问题。
参看代码:

/**
* OuterClass4 是外层类,Printer 局部内置类
*
* @author mercyblitz
*/

public class OuterClass4 {

         public void print( byte[] bytes) {
                 final String message = new String(bytes);
                 /**
                 * 名为Printer LocalClass,没必要把message做为参数传递。
                 */

                 class Printer {
                         private void doPrint() {
                                System.out.println(message);
                        }
                }
                 new Printer().doPrint();
        }

         public static void main(String[] args) {
                 new OuterClass4().print( "AAAAAAA".getBytes());
        }
}
代码 -4
在“代码-4”的示例中,有人可能会说,这看不出什么好处呀?!若是内置类依赖的变量超过4个(Effective Java书中提到超过四个参数的话,不利于维护),那么局部内置类是否是方便维护呢?
顺便提到,匿名内置类是局部内置类的一种。
不难发现,局部内置类的缺点是代码混杂(方法和类混在一块儿),若是依赖局部变量很少的状况下,在必定程度上面,增长了维护成本。
最后的篇幅来总结一下这几种内置类的特色,以及使用场景和设计技巧。
共同特色,不想暴露而且不指望被外部使用或者扩张(强调一下,通常类中私有和包内私用都是好的设计技巧),经过类的四大特性提供更优于方法的方法和外部内实现交互,从而达到良好设计目的。
对于类内置类(Nested Class),适合的绝大多数内置类场景,利于维护。但不适合利用外层类模板参数类型和实例变量。
就实例内置类(Inner Class),适合利用外层类模板参数类型和实例变量,更好的弹性设计。但是加载其类时,必须实例化外部类,形成没必要要开销,所以不是必须,尽可能使用类内置类。
局部内置类(Local Class),适合多局部变量依赖的场景,提升可维护性,相反就不适合。
所以,内置类的设计和其余面向对象设计相似,根据适合的场景来合理设计。 在设计上,没有最好,只有更好 。笔者精力和经验优先,但愿你们指正,谢谢。
================= 此文章的原处不明,我只是保留了原文档
相关文章
相关标签/搜索