2014年4月4日 星期五

[OO 設計模式] Gossip@DesignPattern : Creational - Abstract Factory 模式

來源自 這裡 
Preface: 
如果您需要一組可以隨時抽換的元件,並且希望可以簡單地 一次抽換,則可以考慮使用Abstract Factory。例如視窗程式中視感(Look-and- feel)元件的調換,就是應用的場合. 

Abstract Factory Usage: 
以下是 Abstract Factory 的簡單實現,程式中 Rectangle 依賴於 PointCornerFactory 的公開定義,使用 PointCornerFactory 所提供的一組元件來繪製矩形: 
  1. interface PointCornerFactory {  
  2.     Point getPoint();  
  3.     Corner getCorner();  
  4. }  
  5.   
  6. interface Point {  
  7.     void line(int width);  
  8. }  
  9.   
  10. interface Corner {  
  11.     void leftUp();  
  12.     void rightUp();  
  13.     void leftDown();  
  14.     void rightDown();  
  15. }  
  16.   
  17. class Rectangle {  
  18.     private int width;  
  19.     private int height;  
  20.       
  21.     Rectangle(int width, int height) {  
  22.         this.width = width;  
  23.         this.height = height;  
  24.     }  
  25.       
  26.     void paint(PointCornerFactory factory) {  
  27.         Point point = factory.getPoint();  
  28.         Corner corner = factory.getCorner();  
  29.         corner.leftUp();  
  30.         point.line(width - 2);  
  31.         corner.rightUp();  
  32.         System.out.println();  
  33.         for(int i = 0; i < height - 2; i++) {  
  34.             point.line(width);  
  35.             System.out.println();  
  36.         }  
  37.         corner.leftDown();  
  38.         point.line(width - 2);  
  39.         corner.rightDown();  
  40.         System.out.println();  
  41.     }  
  42. }  
依您所提供的 PointCornerFactoryPoint 與 Corner 實作之不同,可以繪製出不同外觀的矩形,例如: 
  1. public class Main {  
  2.     public static void main(String[] args) {  
  3.         Rectangle rect = new Rectangle(2010);  
  4.         PointCornerFactory factory =  
  5.             new PointCornerFactory() {  
  6.                 public Point getPoint() {  
  7.                     return new Point() {  
  8.                         public void line(int width) {  
  9.                             for(int i = 0; i < width; i++) {  
  10.                                 System.out.print("-");  
  11.                             }  
  12.                         }  
  13.                     };  
  14.                 }  
  15.                   
  16.                 public Corner getCorner() {  
  17.                     return new Corner() {  
  18.                         public void leftUp() { System.out.print('+'); }  
  19.                         public void rightUp() { System.out.print('+'); }  
  20.                         public void leftDown() { System.out.print('+'); }  
  21.                         public void rightDown() { System.out.print('+'); }  
  22.                     };  
  23.                 }  
  24.             };  
  25.         rect.paint(factory);          
  26.     }  
  27. }  
如果您要呈現不同的矩形外觀,則可以提供另一組 PointCornerFactoryPoint 與 Corner 實作,對 Rectangle 而言,就可達成一次抽象所有元件的需求! 

UML class diagram: 
下圖為 AbstractFactory 的類別圖: 
 

圖中 AbstractFactory、Part 指的是,物件必須具有 AbstractFactory、Part 所定義之公 開協定,而非專指 Java 中的 interface 定義。對於靜態語言來說,例如 Java,必須使用型態來宣告變數,因此根 據需求,可以使用 interfact 或 abstract class 來定義 AbstractFactory、Part 所定 義之公開協定。對於動態語言來說,例如 Python,真正的型態資訊是在物件之上(而非變數),因此要求的是物件必須具有 AbstractFactory、 Part 之公開方法(無論是「哪一種」物件). 

AbstractFactory 這個名詞是從的建立可抽換的一組 物件角度來看這個模式,如果將焦點放 在使用抽象工廠物件的方法上,因為方法定義了一個樣版流程,流程中真正需要實際物件運作的部份,則呼叫 callback 物件(工廠物件)來建立,所以從流 程的觀點來看,又稱之為 Template-callback 模式。例 如在範例的 paint() 方法中定義了繪製的流程,真正繪製的物件則是透過 callback 物件(工廠物件)來建立.

2014年4月2日 星期三

[ Java 套件 ] PDFBox - Extract text from PDF file

Preface: 
The Apache PDFBox™ library is an open source Java tool for working with PDF documents. This project allows creation of new PDF documents, manipulation of existing documents and the ability to extract content from documents. Apache PDFBox also includes several command line utilities. Apache PDFBox is published under the Apache License v2.0. 這邊要來看如何利用這個套件, 將 PDF 中的文字內容給輸出. 

在準備工作當然要先去下載該套件, 這邊使用的是 pdfbox-app-1.8.4.jar (pre-built PDFBox standalone binary), 或者你可以去官方的 下載網頁 看看有沒有新版的 Release. 

Extracting text from a PDF file: 
在開始看範例代碼前, 我們先手動建立了一個測試用的 PDF 檔案: 
- test.pdf 
 

要從 PDF 檔案取出文字內容, 會使用到 PDFTextStripper class 中的方法: 
String getText(PDDocument doc) : This will return the text of a document. Remember it returns a 'String'
void writeText(PDDocument doc, Writer outputStream) : This will take a PDDocument and write the text of that document to the print writer.
getPageSeparator(): This will get the page separator.
getPageStart(): Returns the string which will be used at the beginning of a page.

除此之外, 你也可以設定要進行處理的頁數: 
public void setStartPage(int startPageValue): Where startPageValue is the starting page. The first page of the PDF is 1, second page is 2 and so on.
public void setEndPage(int endPageValue): Where endPageValue is the last page that you want to extract. The first page of the PDF is 1 and so on.

接著底下是範例代碼: 
  1. PDDocument pd;  
  2. BufferedWriter wr;  
  3. try {  
  4.     File input = new File("test.pdf"); // The PDF file from where  
  5.                                                 // you would like to  
  6.                                                 // extract  
  7.     File output = new File("test.txt"); // The text file where  
  8.                                                     // you are going to  
  9.                                                     // store the  
  10.                                                     // extracted data  
  11.     pd = PDDocument.load(input);  
  12.     System.out.println(pd.getNumberOfPages());  
  13.     System.out.println(pd.isEncrypted());             
  14.     PDFTextStripper stripper = new PDFTextStripper();  
  15.     //stripper.setStartPage(3); // Start extracting from page 3  
  16.     //stripper.setEndPage(5); // Extract till page 5  
  17.     wr = new BufferedWriter(new OutputStreamWriter(  
  18.             new FileOutputStream(output)));  
  19.     stripper.writeText(pd, wr);  
  20.     if (pd != null) {  
  21.         pd.close();  
  22.     }  
  23.     // I use close() to flush the stream.  
  24.     wr.close();  
  25. catch (Exception e) {  
  26.     e.printStackTrace();  
  27. }  
底下是輸出 test.txt 的內容: 
 

因為是 "文字內容", 所以圖片與連結並沒有辦法在文字檔中顯示. 如果要從 PDF 中取出圖片的話可以參考下面代碼: (pd 變數為 PDDocument 物件
  1. System.out.printf("\t[Info] Extract image(s)...\n");              
  2. List pages = pd.getDocumentCatalog().getAllPages();  
  3. Iterator iter = pages.iterator();             
  4.    while (iter.hasNext()) {  
  5.        PDPage page = (PDPage) iter.next();  
  6.        PDResources resources = page.getResources();  
  7.        Map pdxMap = resources.getXObjects();  
  8.        if (pdxMap != null) {   
  9.            Iterator> pdxMapIter = pdxMap.entrySet().iterator();  
  10.            while(pdxMapIter.hasNext())  
  11.            {  
  12.             Entry e = pdxMapIter.next();  
  13.             if((Object)(e.getValue()) instanceof PDXObjectImage)  
  14.             {  
  15.                 PDXObjectImage imageObj = (PDXObjectImage)e.getValue();  
  16.                 String fn = String.format("%s.jpeg", e.getKey());  
  17.                 System.out.printf("\t\tOutput %s\n", fn);  
  18.                 imageObj.write2file(new File(fn));  
  19.             }  
  20.            }                                      
  21.        }  
  22.    }  
  23.      
  24.    if (pd != null) {  
  25.     pd.close();  
  26. }  
如果要從 PDF 從取出超連結, 則可以參考下面代碼: (page 為 PDPage 物件.
  1. List l = page.getAnnotations();  
  2. for(PDAnnotation pdan:l)  
  3. {  
  4.     if(pdan instanceof PDAnnotationLink)  
  5.     {  
  6.         PDAnnotationLink link = (PDAnnotationLink)pdan;  
  7.         PDActionURI pdl= (PDActionURI)link.getAction();  
  8.         System.out.println("\t\tPDF Link: "+pdl.getURI());  
  9.         wr.append(String.format("Link: %s\n", pdl.getURI()));  
  10.     }  
  11. }  

Supplement: 
Basic PDFBox Tutorial 
PDFBox API 
Stackoverflow: extract images from pdf using pdfbox 
PDFBox extract link information

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...