使用Iterator模式将对象转成String.docx
- 文档编号:8458698
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:13
- 大小:52.36KB
使用Iterator模式将对象转成String.docx
《使用Iterator模式将对象转成String.docx》由会员分享,可在线阅读,更多相关《使用Iterator模式将对象转成String.docx(13页珍藏版)》请在冰豆网上搜索。
使用Iterator模式将对象转成String
操纵JSOM、XML、Javabean等对象时你可能最先想到访问者模式。
但是使用访问者模式很难从调用代码控制回调。
比如,不能有条件的从所有回调的子分支和叶子节点跳过某个分支。
解决这个问题就可以使用Iterator模式遍历整个对象,生成易于开发者阅读和调试的字符串。
该迭代器具备一定的通用性,我在使用XPath查找Java对象和在StackHunter中记录异常的工具中都用到了它。
API
本文主要介绍的两个类:
StringGenerator和ObjectIterator。
字符串生成器
StringGenerator工具类将对象转化为字符串,使对象可读性更好。
可以用它来实现类的toString方法或者把对象的字符串表达作为日志调试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
packagecom.stackhunter.util.tostring.example;
importcom.stackhunter.example.employee.Department;
importcom.stackhunter.example.employee.Employee;
importcom.stackhunter.example.employee.Manager;
importcom.stackhunter.example.people.Person;
importcom.stackhunter.util.tostring.StringGenerator;
publicclassStringGeneratorExample{
publicstaticvoidmain(String[]args){
Departmentdepartment=newDepartment(5775,"Sales")
.setEmployees(
newEmployee(111,"Bill","Gates"),
newEmployee(222,"Howard","Schultz"),
newManager(333,"Jeff","Bezos",75000));
System.out.println(StringGenerator.generate(department));
System.out.println(StringGenerator.generate(newint[]{111,222,333}));
System.out.println(StringGenerator.generate(true));
}
}
StringGenerator.generate()将department,数组和boolean值进行格式化输出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
com.stackhunter.example.employee.Department@129719f4
deptId=5775
employeeList=java.util.ArrayList@7037717a
employeeList[0]=com.stackhunter.example.employee.Employee@17a323c0
firstName=Bill
id=111
lastName=Gates
employeeList[1]=com.stackhunter.example.employee.Employee@57801e5f
firstName=Howard
id=222
lastName=Schultz
employeeList[2]=com.stackhunter.example.employee.Manager@1c4a1bda
budget=75000.0
firstName=Jeff
id=333
lastName=Bezos
name=Sales
[I@39df3255
object[0]=111
object[1]=222
object[2]=333
true
对象迭代器
ObjectIterator使用迭代器模式遍历对象的属性,以键值对形式保存。
对象中的Javabean、集合、数组及map都要进行迭代。
ObjectIterator也会考虑到对象之间循环引用的处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
packagecom.stackhunter.util.tostring.example;
importcom.stackhunter.example.employee.Department;
importcom.stackhunter.example.employee.Employee;
importcom.stackhunter.example.employee.Manager;
importcom.stackhunter.util.objectiterator.ObjectIterator;
publicclassObjectIteratorExample{
publicstaticvoidmain(String[]args){
Departmentdepartment=newDepartment(5775,"Sales")
.setEmployees(
newEmployee(111,"Bill","Gates"),
newEmployee(222,"Howard","Schultz"),
newManager(333,"Jeff","Bezos",75000));
ObjectIteratoriterator=newObjectIterator("somedepartment",department);
while(iterator.next()){
System.out.println(iterator.getName()+"="+iterator.getValueAsString());
}
}
}
通过遍历整个对象生成键值对的集合。
使用getValueAsString()方法而不是toString()格式化输出。
对于原始类型、包装类型、字符串、日期和枚举使用原始的toString()实现。
对于其他类型输出类名和hash值。
ObjectIterator.getDepth()会增加缩进,输出更易读。
调用next()之前使用nextParent()缩短当前分支跳跃到下一属性。
1
2
3
4
5
6
somedepartment=com.stackhunter.example.employee.Department@780324ff
deptId=5775
employeeList=java.util.ArrayList@6bd15108
employeeList[0]=com.stackhunter.example.employee.Employee@22a79c31
firstName=Bill
...
Java对象迭代器的具体实现
实现iterator模式的第一步是创建通用的迭代器接口:
IObjectIterator。
无论遍历的对象是Javabean、数组还是map都可以使用该接口。
1
2
3
4
5
publicinterfaceIObjectIterator{
booleannext();
StringgetName();
ObjectgetValue();
}
使用该接口可以按照单一顺序依次获取当前属性的name和value。
实现了IObjectIterator的类用来处理某一种类型的对象。
大多数类调用getName()返回名称前缀。
ArrayIterator使用了元素的索引:
returnname+"["+nextIndex+"]";。
属性迭代器
PropertyIterator可能是最重要的迭代类。
它使用Javabeanintrospection读取对象属性,将它们转化为键值对序列。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
publicclassPropertyIteratorimplementsIObjectIterator{
privatefinalObjectobject;
privatefinalPropertyDescriptor[]properties;
privateintnextIndex=-1;
privatePropertyDescriptorcurrentProperty;
publicPropertyIterator(Objectobject){
this.object=object;
try{
BeanInfobeanInfo=Introspector.getBeanInfo(object.getClass());
properties=beanInfo.getPropertyDescriptors();
}catch(RuntimeExceptione){
throwe;
}catch(Exceptione){
thrownewRuntimeException(e.getMessage(),e);
}
}
@Override
publicbooleannext(){
if(nextIndex+1>=properties.length){
returnfalse;
}
nextIndex++;
currentProperty=properties[nextIndex];
if(currentProperty.getReadMethod()==null||"class".equals(currentProperty.getName())){
returnnext();
}
returntrue;
}
@Override
publicStringgetName(){
if(currentProperty==null){
returnnull;
}
returncurrentProperty.getName();
}
@Override
publicObjectgetValue(){
try{
if(currentProperty==null){
returnnull;
}
returncurrentProperty.getReadMethod().invoke(object);
}catch(RuntimeExceptione){
throwe;
}catch(Exceptione){
thrownewRuntimeException(e.getMessage(),e);
}
}
}
数组迭代器
ArrayIterator通过反射得到数组的长度,进而检索每个数据元素。
ArrayIterator不关心从getValue()方法返回值的具体细节。
它们一般情况下被传递给PropertyIterator。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
publicclassArrayIteratorimplementsIObjectIterator{
privatefinalStringname;
privatefinalObjectarray;
privatefinalintlength;
privateintnextIndex=-1;
privateObjectcurrentElement;
publicArrayIterator(Stringname,Objectarray){
this.name=name;
this.array=array;
this.length=Array.getLength(array);
}
@Override
publicbooleannext(){
if(nextIndex+1>=length){
returnfalse;
}
nextIndex++;
currentElement=Array.get(array,nextIndex);
returntrue;
}
@Override
publicStringgetName(){
returnname+"["+nextIndex+"]";
}
@Override
publicObjectgetValue(){
returncurrentElement;
}
}
集合迭代器
CollectionIterator与ArrayIterator非常相似。
使用java.lang.Iterable调用它的Iterable.iterator()方法初始化内部迭代器。
Map迭代器
MapIterator遍历java.util.Map的entry。
它并不深入到每个entry的键值对,这个工作由MapEntryIterator类完成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
publicclassMapIteratorimplementsIObjectIterator{
privatefinalStringname;
privateIterator
>entryIterator;
privateMap.Entry
?
>currentEntry;
privateintnextIndex=-1;
publicMapIterator(Stringname,Map
?
>map){
this.name=name;
this.entryIterator=map.entrySet().iterator();
}
@Override
publicbooleannext(){
if(entryIterator.hasNext()){
nextIndex++;
currentEntry=(Entry
?
>)entryIterator.next();
returntrue;
}
returnfalse;
}
...
}
MapEntry迭代器
MapEntryIterator处理java.util.Map的单个entry。
它只返回两个值:
entry的键和值。
与ArrayIterator及其他的类似,如果是复杂类型的话,它的结果可能最终传递给PropertyIterator,作为Javabean处理。
根迭代器
RootIterator返回单个元素——初始节点。
可以把它想成XML文件的根节点。
目的是发起整个遍历过程。
整合
ObjectIterator类作为门面角色(Facade),包装了所有的遍历逻辑。
它根据最后一次getValue()的返回值类型决定哪个IObjectIterator的子类需要实例化。
当子迭代器在内部创建时它在栈中保存当前迭代器的状态。
它也暴露了getChild()和getDepth()方法为调用者展示当前进度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
privateIObjectIteratoriteratorFor(Objectobject){
try{
if(object==null){
returnnull;
}
if(object.getClass().isArray()){
returnnewArrayIterator(name,object);
}
if(objectinstanceofIterable){
returnnewCollectionIterator(name,(Iterable
>)object);
}
if(objectinstanceofMap){
returnnewMapIterator(name,(Map
?
>)object);
}
if(objectinstanceofMap.Entry){
returnnewMapEntryIterator(name,(Map.Entry
?
>)object);
}
if(isSingleValued(object)){
returnnull;
}
returnnewPropertyIterator(object);
}catch(RuntimeExceptione){
throwe;
}catch(Exceptione){
thrownewRuntimeException(e.getMessage(),e);
}
}
字符串生成器的实现
已经看到如何遍历对象中的所有属性。
最后的工作就是让输出更加美观,以及增加一些限制条件(比如不能创建一个GB级大小的字符串)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
publicstaticStringgenerate(Objectobject){
Strings="";
ObjectIteratoriterator=newObjectIterator("object",object);
...
while(iterator.next()){
if(s.length()>=MAX_STRING_LENGTH){
returns;
}
if(iterator.getChild()>=MAX_CHILDREN){
iterator.nextParent();
continue;
}
StringvalueAsString=iterator.getValueAsString();
s+=System.lineSeparator();
s+=indent(iterator.getDepth())+truncateString
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 使用 Iterator 模式 对象 转成 String