`

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> 内部定义不少的类内置类。

使用下了代码实例补充说明上述:

package  org.mercy.design;

 

/**

  *   OuterClass   是外层类,NestedClass   类内置类

  *   @author   mercyblitz

  */

public   class  OuterClass {

/**

  *   private   final   static   是类内置类的通用设计技巧

  */

private   final   static   class   NestedClass  {

}

}

代码 -1

 

如果 OuterClass类中有实例变量的话,显然 NestedClass 是不可见的,也是不适用的(因为它是类的一部分)。

这个时候,利用实例内置类可以解决这类问题。

示例代码如下:

package  org.mercy.design;

 

/**

  *   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 利用 OuterClass2 message 字段作为输出。

可能有人会说,InnerClass 这种实例内,为了得到这个类,不得不创建一个实例,太浪费 资源 了,为什么不直接把OuterClass 实例作为参数,直接传入到 InnerClass 的方法呢?

没错,可以那么做。不过单从访问外层类的实例变量而言,利用实例内置类是有点显得 浪费。 如果 客户端利用了泛型编程的话,情况就会不同。

总所周知, 泛型设计能够提高灵活性,可是也有很多限制。模版参数类型是跟随其寄主类的, 模板参数类型是不会写入class 文件中的,这就是为什么反射( Reflection )不能解析出类的模板参数类型。但是,模板参数类型在实例(对象)范围是可用的(或可视的) 。如果内置类中想要利用外层类的模板参数类型的话,那么实例内置类就有很大用处。

例子如下:

package  org.mercy.design;

 

/**

  *   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) 更为方便,因为局部内置类是在块中(方法也是一种特殊的块)定义的,这样就很好的解决了上下文的参数传递问题。

参看代码:

package  org.mercy.design;

 

/**

  *   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书中提到超过四个参数的话,不利于维护),那么局部内置类是不是方便维护呢?

顺便提到,匿名内置类是局部内置类的一种。

不难发现,局部内置类的缺点是代码混杂(方法和类混在一起),如果依赖局部变量不多的情况下,在一定程度上面,增加了维护成本。

(其他内容,见附件)

分享到:
评论
10 楼 mib168 2010-07-22  
面向对象设计要真想弄精了也需要点功夫 呵呵
9 楼 jychenok 2010-07-21  
mercyblitz 写道
jychenok 写道
匿名内部类的方法中如果对外部变量的引用,则需要时final的,如果在方法中需要改变其引用,有比较好点的实现么?
比如:
Java 代码

   1. final Boolean isReady = false; 
   2. notifyTaskExecutor.execute(new Runnable(){ 
   3.  
   4.     @Override 
   5.     public void run() { 
   6.         notifys.addAll(notifyBo.getNotifys(maxNum)); 
   7.         isReady = true; 
   8.     } 
   9. }); 

final Boolean isReady = false;
notifyTaskExecutor.execute(new Runnable(){

    @Override
    public void run() {
        notifys.addAll(notifyBo.getNotifys(maxNum));
        isReady = true;
    }
});


我目前是这样解决的:
Java 代码

   1. final Boolean[] isReady = {false}; 
   2. notifyTaskExecutor.execute(new Runnable(){ 
   3.  
   4.     @Override 
   5.     public void run() { 
   6.         notifys.addAll(notifyBo.getNotifys(maxNum)); 
   7.         isReady[0] = true; 
   8.     } 
   9. }); 

final Boolean[] isReady = {false};
notifyTaskExecutor.execute(new Runnable(){

    @Override
    public void run() {
        notifys.addAll(notifyBo.getNotifys(maxNum));
        isReady[0] = true;
    }
});


但是代码会很奇怪,能不能有其他的解决方式呢?比如Boolean自己改变自己的值?


还可以使用AtomicBoolean.


这种方式可行,谢谢了,呵,试了一下
public final void set(boolean newValue) {
        value = newValue ? 1 : 0;
}
8 楼 mercyblitz 2010-07-15  
jychenok 写道
匿名内部类的方法中如果对外部变量的引用,则需要时final的,如果在方法中需要改变其引用,有比较好点的实现么?
比如:
Java 代码

   1. final Boolean isReady = false; 
   2. notifyTaskExecutor.execute(new Runnable(){ 
   3.  
   4.     @Override 
   5.     public void run() { 
   6.         notifys.addAll(notifyBo.getNotifys(maxNum)); 
   7.         isReady = true; 
   8.     } 
   9. }); 

final Boolean isReady = false;
notifyTaskExecutor.execute(new Runnable(){

    @Override
    public void run() {
        notifys.addAll(notifyBo.getNotifys(maxNum));
        isReady = true;
    }
});


我目前是这样解决的:
Java 代码

   1. final Boolean[] isReady = {false}; 
   2. notifyTaskExecutor.execute(new Runnable(){ 
   3.  
   4.     @Override 
   5.     public void run() { 
   6.         notifys.addAll(notifyBo.getNotifys(maxNum)); 
   7.         isReady[0] = true; 
   8.     } 
   9. }); 

final Boolean[] isReady = {false};
notifyTaskExecutor.execute(new Runnable(){

    @Override
    public void run() {
        notifys.addAll(notifyBo.getNotifys(maxNum));
        isReady[0] = true;
    }
});


但是代码会很奇怪,能不能有其他的解决方式呢?比如Boolean自己改变自己的值?


还可以使用AtomicBoolean.
7 楼 mercyblitz 2010-07-15  
jychenok 写道
匿名内部类的方法中如果对外部变量的引用,则需要时final的,如果在方法中需要改变其引用,有比较好点的实现么?
比如:
Java 代码

   1. final Boolean isReady = false; 
   2. notifyTaskExecutor.execute(new Runnable(){ 
   3.  
   4.     @Override 
   5.     public void run() { 
   6.         notifys.addAll(notifyBo.getNotifys(maxNum)); 
   7.         isReady = true; 
   8.     } 
   9. }); 

final Boolean isReady = false;
notifyTaskExecutor.execute(new Runnable(){

    @Override
    public void run() {
        notifys.addAll(notifyBo.getNotifys(maxNum));
        isReady = true;
    }
});


我目前是这样解决的:
Java 代码

   1. final Boolean[] isReady = {false}; 
   2. notifyTaskExecutor.execute(new Runnable(){ 
   3.  
   4.     @Override 
   5.     public void run() { 
   6.         notifys.addAll(notifyBo.getNotifys(maxNum)); 
   7.         isReady[0] = true; 
   8.     } 
   9. }); 

final Boolean[] isReady = {false};
notifyTaskExecutor.execute(new Runnable(){

    @Override
    public void run() {
        notifys.addAll(notifyBo.getNotifys(maxNum));
        isReady[0] = true;
    }
});


但是代码会很奇怪,能不能有其他的解决方式呢?比如Boolean自己改变自己的值?



你可以利用ThreadLocal来做。
6 楼 jychenok 2010-07-15  
匿名内部类的方法中如果对外部变量的引用,则需要时final的,如果在方法中需要改变其引用,有比较好点的实现么?
比如:
Java 代码

   1. final Boolean isReady = false; 
   2. notifyTaskExecutor.execute(new Runnable(){ 
   3.  
   4.     @Override 
   5.     public void run() { 
   6.         notifys.addAll(notifyBo.getNotifys(maxNum)); 
   7.         isReady = true; 
   8.     } 
   9. }); 

final Boolean isReady = false;
notifyTaskExecutor.execute(new Runnable(){

    @Override
    public void run() {
        notifys.addAll(notifyBo.getNotifys(maxNum));
        isReady = true;
    }
});


我目前是这样解决的:
Java 代码

   1. final Boolean[] isReady = {false}; 
   2. notifyTaskExecutor.execute(new Runnable(){ 
   3.  
   4.     @Override 
   5.     public void run() { 
   6.         notifys.addAll(notifyBo.getNotifys(maxNum)); 
   7.         isReady[0] = true; 
   8.     } 
   9. }); 

final Boolean[] isReady = {false};
notifyTaskExecutor.execute(new Runnable(){

    @Override
    public void run() {
        notifys.addAll(notifyBo.getNotifys(maxNum));
        isReady[0] = true;
    }
});


但是代码会很奇怪,能不能有其他的解决方式呢?比如Boolean自己改变自己的值?
5 楼 mercyblitz 2010-05-10  
android9i 写道
JE上那些管理员就是这么2

内部类还是非常强大的,尤其在android的界面构建时,更好做到界面与展现分离~



呵呵,是啊,感谢你回帖啊!
4 楼 android9i 2010-05-10  
JE上那些管理员就是这么2

内部类还是非常强大的,尤其在android的界面构建时,更好做到界面与展现分离~
3 楼 mercyblitz 2010-05-09  
月落码农 写道
呵呵! 杯具,楼主的帖被评为新手帖。。LZ加油



呵呵,好的,很多人认为这个东西简单,不过呢,很少看过之后,进行思考。
2 楼 月落码农 2010-05-09  
呵呵! 杯具,楼主的帖被评为新手帖。。LZ加油
1 楼 hellojinjie 2010-05-07  
突然想起来,,上星期写了个内部类,忘了用private   final

引用
/**

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

  */

private   final   class   InnerClass  {

public   void  setData(T newData) {

OuterClass3. this . data  = newData;

// DOES Other things

}

}

相关推荐

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

    本文档“Java面向对象设计最佳实践—内置类设计”深入探讨了如何利用Java的内置类机制来优化代码结构,提高可读性和可维护性。以下是基于这个主题的详细知识点: 1. **内置类(Inner Classes)的概念**: 内置类...

    Java语言与面向对象程序设计-印旻ppt

    5. **设计模式**:面向对象设计模式是解决特定问题的最佳实践,如单例模式、工厂模式、观察者模式等,这些模式在Java编程中广泛应用。 印旻的PPT将详细解释这些概念,并通过实例和练习帮助学习者理解和应用。通过...

    《Java面向对象程序设计》例子源代码

    《Java面向对象程序设计》是一本深入探讨Java编程语言中面向对象特性的经典教材。这本书通过丰富的实例,帮助读者理解并掌握如何利用Java进行高效、可靠的面向对象编程。以下是一些核心的知识点: 1. 面向对象基础...

    java面向对象基础、高级pdf讲义

    15. 设计模式:设计模式是解决常见软件设计问题的最佳实践。如工厂模式、单例模式、观察者模式、装饰器模式等,都是面向对象编程中的重要工具。 以上就是Java面向对象的基础和高级知识点,通过深入学习和实践,...

    面向对象程序设计(Java)教学课件

    15. 设计模式:设计模式是解决常见编程问题的最佳实践,例如工厂模式、单例模式、观察者模式等,它们在Java编程中广泛使用。 通过学习这些Java面向对象编程的核心概念,学习者可以更好地理解和应用Java语言,从而...

    JAVA语言与面向对象程序设计

    教程中可能还涵盖了异常处理的最佳实践、集合框架的高效使用、多线程编程的注意事项,以及如何利用Java进行系统级开发等内容。 在学习过程中,配合邓老师的电子教案,结合实际编程练习,将有助于巩固理论知识,提升...

    面向对象分析与设计(培养思维很好的教程)

    其内置的类库和特性,如访问修饰符、构造函数、接口、异常处理等,使得面向对象的设计更为便捷。在Java中,我们还可以利用反射机制来动态地创建对象和调用方法,进一步提高了灵活性。 这个教程中可能包含的具体内容...

    孙卫琴 《Java面向对象编程》源代码

    《Java面向对象编程》是孙卫琴著作的一本关于Java编程技术的书籍,重点在于讲解如何使用面向对象的思想和Java语言进行程序设计。该书的源代码提供了丰富的实例,帮助读者深入理解书中理论知识,实践操作,提升编程...

    面向对象java课件

    设计模式是解决常见问题的最佳实践,例如工厂模式、单例模式、观察者模式等,它们在实际开发中具有广泛应用。 6. **事件处理**: 在图形用户界面(GUI)编程中,事件处理是用户交互的关键,Java提供了AWT和Swing...

    java学习笔记-----给java初学者

    通过深入学习和实践这份"JAVA学习笔记"中的内容,初学者不仅可以掌握Java编程的基础,还能进一步了解高级特性和最佳实践,从而成为一名熟练的Java开发者。这份笔记的实用性确保了学习过程的高效性和趣味性,让学习...

    西北工业大学SSD3(面向对象程序设计课件包括课程所用源代码)

    在OOP中,我们还会接触到设计模式,这是在特定场景下解决常见问题的最佳实践。例如,单例模式确保一个类只有一个实例;工厂模式提供了一种创建对象的最佳方式,而无需暴露创建逻辑;观察者模式则用于定义对象之间的...

    Java语言程序设计源代码

    此外,书中可能还涉及了一些设计模式和最佳实践,这些都是专业开发者的必备素养。 总而言之,《Java语言程序设计》的源代码是一份宝贵的资源,它可以帮助你深入学习Java编程语言,理解其核心概念和特性,从而成为一...

    自考java 04747《Java语言程序设计(一)》教材电子版

    《Java语言程序设计(一)》是自考Java专业的一门重要课程,旨在帮助学习者掌握Java编程的基础知识和技能。这门课程涵盖了Java语言...同时,不断关注Java的新特性和最佳实践,能够让你在这个快速发展的领域保持竞争力。

    java设计与实践

    Java设计与实践是Java开发领域中的重要主题,涵盖了软件开发的多个方面,包括但不限于编程基础、面向对象设计、异常处理、集合框架、多线程、网络编程、输入/输出(I/O)、数据库交互以及设计模式等。在这个广阔的...

    Java 中的设计模式 - jdon

    设计模式是软件工程中的一种最佳实践,它总结了在特定上下文中解决常见问题的经验和方法,为软件设计提供了可复用的解决方案。 在Java编程中,设计模式扮演着至关重要的角色,它们能够提高代码的可读性、可维护性和...

    源代码-Java程序设计习题与实践(实践题部分).rar

    12. **设计模式**:在实践题中,学生可能会接触到一些常见的设计模式,如单例模式、工厂模式、观察者模式等,这些都是解决特定编程问题的最佳实践。 这些知识点是Java程序设计的基本组成部分,通过实践题目,学生...

    Java程序设计实训教程-电子教案、源代码.rar

    2. **面向对象编程**:Java是一种面向对象的语言,因此理解类、对象、继承、封装和多态这些核心概念至关重要。类是创建对象的模板,对象则是程序中的实体;继承允许子类继承父类的属性和行为;封装是将数据和操作...

    Java高级程序设计

    8. **设计模式**:设计模式是面向对象编程中的最佳实践,如单例模式、工厂模式、观察者模式等。熟悉这些模式能提高代码的可维护性和可扩展性。 9. **Java EE**:如果涉及到企业级开发,Java的服务器端技术如Servlet...

    《新编Java语言程序设计》(清华出版社)习题参考答案.rar

    1. 面向对象:Java支持类、对象、继承、封装和多态等面向对象的特性,使得代码更易于维护和扩展。 2. 自动内存管理:通过垃圾回收机制,Java自动处理内存分配和释放,避免了常见的内存泄漏问题。 3. 异常处理:Java...

    Java程序设计课程教学实践.zip

    通过"Java程序设计课程教学实践.pdf"这份文档,学生不仅能够学习到Java编程的基础知识,还能了解到实际项目中的最佳实践,从而提升编程技能和问题解决能力。无论是初学者还是有一定经验的开发者,都能从中受益。

Global site tag (gtag.js) - Google Analytics