- 浏览: 887464 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
小宇宙_WZY:
膜拜一下大神,解决了我一个大问题,非常感谢 orz
【解惑】深入jar包:从jar包中读取资源文件 -
JKL852qaz:
感谢,遇到相同的问题!
【解惑】深入jar包:从jar包中读取资源文件 -
lgh1992314:
为什么java中调用final方法是用invokevirtua ...
【解惑】Java动态绑定机制的内幕 -
鲁曼1991:
说的都有道理,protected只能被同一级包的类所调用
【解惑】真正理解了protected的作用范围 -
鲁曼1991:
...
【总结】String in Java
装饰者模式
继承是OOP程序设计的一大特点,但其实对于很多复杂问题来说,利用继承关系处理问题往往具有很高的耦合性,不利于代码的维护。利用组合很大程度上可以做到降耦。多
用组合,少用继承是OOP设计的重要思想。
装饰者模式给我们提出了一个好的OOP设计原则:类应该对扩展开放,对修改关闭 。
这句话的意思就是,如果问题发生改变,衡量一个好的设计标准就是:你不需要修改类中的代码,只需要扩展新类来适应新的行为。
《Head First Design Patterns》对装饰者模式说的很清楚。这里稍微注意几点:
(1) 装饰者和被装饰者必须具有相同的超类型。
(2) 装饰者即可以包装被装饰者,也可以包装装饰者。往往利用多层包装来达到目的。
(3) 装饰者中组合了被装饰者对象,这是装饰类的关键特征。正是由于这种组合,使得我们能够随心所欲的通过嵌套装饰来动态扩展行为。
Java IO框架的装饰者设计
在java类库中的IO流就是用装饰者模式设计的。JDK5.0中60多个IO流类组成了四大家族:InputStream,OutputStream,Reader,Writer。
InputStream/OutputStream是对字节序列进行操作的抽象类。
Reader/Writer是基于Unicode代码单元进行操作的抽象类。
这四大家族中大量的类都具有自己不同的功能,要做到方便的完成各种输入输出行为。必须组合使用这些类,装饰者模式是再好不过的设计了。那么IO类库如何实现装饰者模式的,我们看看几个类的部分源码: //InputStream:字节序列输入类鼻祖 public abstract class InputStream implements Closeable { //最基本的读取字节的抽象方法,供子类扩展。 public abstract int read() throws IOException; } //FileInputStream: 读取文件中的字节流类 继承InputStream public class FileInputStream extends InputStream{ //构造器 public FileInputStream(String name) throws FileNotFoundException { //....... } //本地方法,与操作系统低层交互的具体读入方法 public native int read() throws IOException; } //FilterInputStream: 过滤流类,起装饰器作用,用于对输入装配各种功能 public class FilterInputStream extends InputStream { //用于记录被装饰者,也就是需要装配新功能的InputStream对象 protected volatile InputStream in; protected FilterInputStream(InputStream in) { //构造装饰器 this.in = in; //设置需要被包装InputStream对象 } //读入字节 public int read() throws IOException { return in.read(); } } //BufferedInputStream: 使输入流具有缓冲功能,是一种可以装配缓冲功能的装饰器,继承FilterInputStream public class BufferedInputStream extends FilterInputStream { //构造器 public BufferedInputStream(InputStream in) { this(in, defaultBufferSize); //in就是被装配缓冲功能的InputStream } }
这四个类同属于InputStream家族,他们就是一个经典的装饰器模式设计。其中 IO类库中还有很多其他的装饰器,比如处理基本数据类型的DataInputStream,处理ZIP文件流的ZipInputStream,等等。只要我们想的到的行为,都可以用这些装饰器包装组合来完成。就这一点,装饰器绝对是Perfect。 Java Collection框架的装饰者设计 问题提出:当我们即需要List结构的可重复存储,又需要Set中高效率的查找操作。怎么办? 最好的解决办法就是:先用List存储好所有的数据,当需要查找某个元素的时候,将List对象包装成Set类型进行查找,然后返回List数据结构和Set的查找结果。将两种不同类别的功能合并使用,装饰者模式(包装器)无疑是最好的设计。
InputStream 具有读入功能的抽象被装饰器。
FileInputStream 具有读入文件功能的具体被装饰器
FilterInputStream 具备装饰器的抽象意义。
BufferedInputStream 具有具体功能(缓冲功能)的装饰器。
这个时候后我想设计一个具有缓冲功能的读取文件中的字节的行为:
在JDK类库种,集合类也使用了这种设计模式,我们看看这种设计模式给集合类库带来了什么好处?
所有实现Collection接口的集合类都有一种构造器,其参数是集合类的引用。
//ArrayList的包装构造器
public ArrayList(Collection<? extends E> c) { ..... }
//LinkedList的包装构造器
public LinkedList(Collection<? extends E> c) { ..... }
//HashSet的包装构造器 public HashSet(Collection<? extends E> c) { ..... }
我们可以通过这种构造直接将一种Collection类对象包装成另一种。
//Collection类的打包过程 import java.util.*; public class TestDemo{ public static void main(String[] args){ ArrayList<String> list=new ArrayList<String>(); list.add("a1"); list.add("a1"); list.add("b1"); list.add("c1"); System.out.println("List ="+list); HashSet<String> set=new HashSet<String>(list);//包装 System.out.println("Set ="+set); } } /*运行结果: List =[a1, a1, b1, c1] Set =[b1, a1, c1] */
值得注意的是:包装过程中集合类的存储数据类型必须兼容Collection<? extends E>。也就是被 包装 集合中数据类型必须是包装集合数据类型的子类或两者类型相同 。例如:被包装的ArrayList中的数据类型是Manager,它是包装的HashSet中数据类型Employee的子类。否则编译器不会通过。 这也是为了保证类型的自动向上转型的特性。被包装的类型可以通过包装操作自动向上转型成父类。
//包装过程中泛型类型的兼容 import java.util.*; class Employee{ } class Manager extends Employee{ } public class TestDemo{ public static void main(String[] args){ /*error : ArrayList<Employee> list=new ArrayList<Employee>(); HashSet<Manager> set=new HashSet<Manager>(list);*/ //正确: ArrayList<Manager> list=new ArrayList<Manager>(); HashSet<Employee> set=new HashSet<Employee>(list); } }
顺便提一句: 集合框架中的Map类型是不能和Collection类型互相包装的,他们的数据结构毕竟相差太大了 。(~你不想在商店买到的可乐里包装的是医用酒精吧)
这里提一下我一直的疑问:Collection的名字有点让人费解,刚学的时候还以为他就是所有集合类的基础接口,毕竟Collection的中文意思就是集合吗? 后来发现Map类型和
Collection没有一点关系,不知道Java的设计者是怎么取名字的,或者有难言之隐吧。
数组转化为集合:Array的asList()。
String[] values=".....";
HashSet<String> hs=new HashSet<String>(Array.asList(values));
集合转化为数组:Collection的toArray()。
HashSet<String> hs=new HashSet<String>();
Object[] o=hs.toArray();
千万要注意:toArray()方法返回的是一个Object[]数组。而且你无法将其强制类型转化成你需要的数组类型。(关于类类型间的强制类型转换,我在《【解惑】Java类型间的转型 》一文中有详细阐述)
String[] array=(String[])hs.toArray(); //error
我们必须使用toArray的变体来做到这一点,为toArray传递一个长度为0的随意类型的数组。然后,返回的数组就是这个类型了。
String[] array=hs.toArray(new String[0]);
发表评论
-
NIO
2010-08-05 10:36 0在JDK1.4以前,I/O输入输出处理,我们把它称为旧 ... -
【总结】Java线程同步机制深刻阐述
2010-05-16 10:21 5928全文转载:http://www.iteye ... -
【JDK优化】java.util.Arrays的排序研究
2010-05-12 21:06 9104作者题记:JDK中有很多算法具有优化的闪光点,值得好好研究。 ... -
【JDK优化】 Integer 自动打包机制的优化
2010-03-12 19:14 4071我们首先来看一段代码: Integer i=100; In ... -
【总结】Java与字符编码问题详谈
2009-12-30 09:11 9343一、字符集和字符编码方式 计算机只懂得0/1两种信号 ... -
【解惑】 正确理解线程等待和释放(wait/notify)
2009-12-29 13:40 19644对于初学者来说,下面这个例子是一个非常常见的错误。 /** ... -
【解惑】JVM如何理解Java泛型类
2009-12-16 11:08 12215//泛型代码 public class Pair<T& ... -
【解惑】正确的理解this 和 super
2009-12-05 09:46 4406转载: 《无聊 ... -
【解惑】真正理解了protected的作用范围
2009-11-21 18:00 4993一提到访问控 ... -
【总结】String in Java
2009-11-21 17:52 10795作者:每次上网冲杯Java时,都能看到关于String无休无止 ... -
【解惑】真正理解了protected的作用范围
2009-11-16 17:11 585一提到访问控制符protected,即使是初学者 ... -
总结Java标准类库中类型相互转化的方法
2009-11-09 21:57 210组一: ☆ String → byte[ ... -
方法没覆盖住带来的烦恼
2009-11-05 09:18 100Object类是所有类的祖宗,它的equals方法比较的 ... -
【解惑】数组向上转型的陷阱
2009-11-03 11:44 1835问题提出: 有两个类Manager和Em ... -
【总结】java命令解析以及编译器,虚拟机如何定位类
2009-11-01 16:25 5740学Java有些日子了,一直都使用IDE来写程序。这 ... -
【解惑】剖析float型的内存存储和精度丢失问题
2009-10-26 15:10 15806问题提出:12.0f-11.9f=0.10 ... -
【解惑】领略内部类的“内部”
2009-10-19 15:38 3532内部类有两种情况: (1) 在类中定义一个类(私有内部类 ... -
【解惑】深入jar包:从jar包中读取资源文件
2009-10-08 21:13 65383我们常常在代码中读取一些资源文件(比如图片,音乐,文 ... -
【解惑】理解java枚举类型
2009-09-26 09:37 3351枚举类型是JDK5.0的新特征。Sun引进了一个全新的关键字e ... -
编写自己的equals方法
2009-09-20 14:18 129在我的《令人头疼的"相等"关 ...
相关推荐
二十一、 设计模式★★★★★ 136 设计模式简介 136 单例设计模式:★★★★★ 156 工厂模式★★★★★ 159 抽象工厂模式★★★★★ 163 建造者模式 170 原型模式 177 适配器模式 182 桥接模式 188 过滤器模式 192 ...
Java基础笔记分为 Java基础篇 和 Java加强篇 Java基础篇包括: 1. Java环境搭建、Java快速入门、IDEA开发工具 2. Java基础语法、类型转换、运算符、Scanner 3. 分支结构、循环结构...14. XML、解析、工厂模式和装饰模式
Java常见面试题: 1. 什么是 Java?它的特点是什么? 2. 解释面向对象编程(OOP)的概念和特点...列举几个常见的设计模式。 19. 解释 Java 中的序列化和反序列化的概念。 20. 如何处理并发编程中的线程安全和性能问题?
java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类...
java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类。...
java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类。...
java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类。...
java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类...
java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类...
java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类...
java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类...
java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类...
Session Bean 还可以再细分为 Stateful Session Bean 与 Stateless Session Bean ,这两种的 Session Bean都可以将系统逻辑放在 method之中执行,不同的是 Stateful Session Bean 可以记录呼叫者的状态,因此通常来...
MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan ...
Session Bean 还可以再细分为 Stateful Session Bean 与 Stateless Session Bean ,这两种的 Session Bean都可以将系统逻辑放在 method之中执行,不同的是 Stateful Session Bean 可以记录呼叫者的状态,因此通常...
7.4 软件的可维护与复用设计原则194 7.5 本章练习199 第8章 8.1 内部类和内部接口202 8.1.1 非静态成员内部类203 8.1.2 局部内部类206 8.1.3 静态内部类209 8.1.4 匿名内部类211 8.2 对象包装器213 8.3 装箱和拆箱...