「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」
PDF神器iText英文版翻译与学习
作者: 薛大郎.
英文原版:iText in Action 2nd Edition.pdf
坚持. 分享. 成长. 利他 !
一. 前言
人心里的成见,就像一座大山
每个人的出生背景和成长环境都不同, 价值观和喜好也非常的不同, 不过还好, 佛家说, 是五百次回眸的执着才换来今生的擦肩而过,是千年不变的守候才有了今生的默默相守?十年修得同船渡.百年修得共枕眠.
从这两个角度看来, 对待身边的人就应该像稻盛和夫
说的那样, 要心存感恩之心
. 不要总是按照自己的固有思维对他人囚禁
, 其实有这些成见之人也正是被自己囚禁起来的犯人
.
当我走出囚室迈向通往自由的监狱大门时,我已经清楚,自己若不能把痛苦与怨恨留在身后,那么其实我仍在狱中。 ----纳尔逊·罗利赫拉赫拉·曼德拉
二.正文.
4. 学习使用Element高级元素
- 首先看下Element的UML关系图
// 从源码来看可以添加所有上边实现了Element接口的类
public boolean add(Element element) throws DocumentException {
// 关闭状态的Document是不可以添加元素的
if (close) {
throw new DocumentException(MessageLocalization.getComposedMessage("the.document.has.been.closed.you.can.t.add.any.elements"));
}
// 没有打开的状态也不可以添加元素, 大部分的Element#isContent()返回true;
if (!open && element.isContent()) {
throw new DocumentException(MessageLocalization.getComposedMessage("the.document.is.not.open.yet.you.can.only.add.meta.information"));
}
boolean success = false;
// 自动添加章节数元素 特殊处理
if (element instanceof ChapterAutoNumber) {
chapternumber = ((ChapterAutoNumber)element).setAutomaticNumber(chapternumber);
}
// DocListener 也是Element的实现, 需要特殊对待, 而且也可以看出来Document可添加多个文档监听类
for (DocListener listener : listeners) {
success |= listener.add(element);
}
// 大元素的特殊处理,
if (element instanceof LargeElement) {
LargeElement e = (LargeElement)element;
if (!e.isComplete())
e.flushContent();
}
return success;
}
当看完Document#add源码的时候, 是不是感觉就懵了. 那我们HelloWorld是怎样添加进Paragraph的.
别急, 其实这也是iText的coder给我们做好的设计, 接下来我们就继续往下看, 但是这里还是要给大家说下, Java作为一个Object Oriented
语言, 抽象的特性是我们作为开发必须要去悟道的一个点, 代码结构上的设计, 抽象的设计, 以及设计模式的运用都是优秀源码中我们看到的, 而且我们应该追逐的和理解的.
设计优秀的源码高扩展性, 高内聚低耦合, 优美, 易编码;
// 通过查看PdfWriter的源码, getInstance重载也都是使用的addDocListener方法添加一个**Documnet的子类PdfDocumnet**来监听document, 从而所有Document的add方法调取PdfDocument#add方法
public static PdfWriter getInstance(final Document document, final OutputStream os)
throws DocumentException {
PdfDocument pdf = new PdfDocument();
document.addDocListener(pdf);
PdfWriter writer = new PdfWriter(pdf, os);
pdf.addWriter(writer);
return writer;
}
那接下来看PdfDocument的添加方法, 我想大家也大概都想到了就是各种元素的特殊处理.
// ... 为省略部分代码实现
public boolean add(final Element element) throws DocumentException {
if (writer != null && writer.isPaused()) {
return false;
}
try {
if (element.type() != Element.DIV) {
flushFloatingElements();
}
// 源码 => TODO refactor this uber long switch to State/Strategy or something ...
// 对于目前(5.x版本)的设计来说, 暂时这样也是非常合理的, element.type()返回的为Element的int常量, 对于int的设计大家是不是想起来了Thread的状态int设计呢?
switch(element.type()) {
// Information (headers)
case Element.HEADER:
info.addkey(((Meta)element).getName(), ((Meta)element).getContent());
break;
case Element.TITLE:
info.addTitle(((Meta)element).getContent());
break;
case Element.SUBJECT:
info.addSubject(((Meta)element).getContent());
break;
case Element.KEYWORDS:
info.addKeywords(((Meta)element).getContent());
break;
case Element.AUTHOR:
info.addAuthor(((Meta)element).getContent());
break;
case Element.CREATOR:
info.addCreator(((Meta)element).getContent());
break;
case Element.LANGUAGE:
setLanguage(((Meta)element).getContent());
break;
case Element.PRODUCER:
...
break;
case Element.CREATIONDATE:
...
break;
case Element.CHUNK: {
...
break;
}
case Element.ANCHOR: {
...
break;
}
case Element.ANNOTATION: {
...
break;
}
case Element.PHRASE: {
...
break;
}
case Element.PARAGRAPH: {
...
break;
}
case Element.SECTION:
case Element.CHAPTER: {
...
break;
}
case Element.LIST: {
...
break;
}
case Element.LISTITEM: {
...
break;
}
case Element.RECTANGLE: {
...
break;
}
case Element.PTABLE: {
...
break;
}
// 熟悉java 的都知道 这几个case将用同一个逻辑然后再IMGTEMPLATE:break出来.
case Element.JPEG:
case Element.JPEG2000:
case Element.JBIG2:
case Element.IMGRAW:
case Element.IMGTEMPLATE: {
...
break;
}
case Element.YMARK: {
...
break;
}
case Element.MARKED: {
...
break;
}
case Element.WRITABLE_DIRECT:
...
break;
case Element.DIV:
...
break;
default:
return false;
}
// 记录添加的最后一个元素, 用于处理是否换行和同一个段落要建新页面的逻辑处理
lastElementType = element.type();
return true;
}
catch(Exception e) {
throw new DocumentException(e);
}
}
在本篇最后, 还是想跟读者多聊一些关于我们在平常开发过程中, 所有的需求都很急, 但是不是咱们编写the Mountain of Shit
的理由, 当某些逻辑或者判断, 以及配置等等再出现2次时, 我们就需要看是否应该提出来, 要么作为新方法进行稍微优化, 如果出现3次, 那就需要我们很好的设计了, 或者选择相应的设计模式, 或者不想过度设计可以使用简易的工厂模式来处理, 如果出现3次以上, 那就需要我们进行很好的设计;
也许我们不是架构师, 为什么要这样要求自己呢, 可以这样想, 只是不被后来维护者爆出WTF
也是不错的.