I have an object A used to replace text sequences in a given Word document. To construct A, the following dependency has to be passed to its constructor:
- ReplaceBehaviour: an implementation of an abstract Visitor (Design Pattern) used to replace different types of content (e.g., text, images, tables) in the Word document
A internally uses ApachePOI to process Word documents. The replacement logic is defined in the Visitor implementation (B) which is passed as a dependency to A. However, to perform the replacement, B also requires C. In terms of ApachePOI, C is a XWPFDocument (https://poi.apache.org/apidocs/dev/org/apache/poi/xwpf/usermodel/XWPFDocument.html). Executing the replaceContent method of A, three things happen in the following order:
- A instantiates a new XWPFDocument (C) based upon the input file path of the Word document
- A assigns C to the visitor B
- Visitor is executed on the objects that should be replaced
If I am correct, A is a Facade (GoF design pattern), because it provides an “easier” interface to replace content in the Word document. A is considered “easier”, because it encapsulates the entire Apache-POI related code. However, A internally creates the XWPFDocument C and (also internally) assigns it to the Visitor B. I am not sure if assigning C to the Visitor before executing B is considered good practice? If not, how can we solve this in a better way? Alternatively, one could construct C and B, assign C to B and then pass both of them to A on construction. But then, a client using A would have to instantiate a ApachePOI-class (XWPFDocument) him/herself which defeates the purpose of the Facade. The following pseudo code summarizes the problem described above:
public class A { private IReplaceVisitor b; public A(IReplaceVisitor b) { this.b = b; } public void replaceContent(List<ReplacementObject> objectsToReplace, String inputWordPath, String outputWordPath) { XWPFDocument c = new XWPFDocument(inputWordPath); b.setDocument(c); foreach act in objectsToReplace execute act.accept(b); // write updated XWPFDocument c to disk } } // use of A somewhere else ... public void testReplacement(List<ReplacementObject> objectsToReplace) { IReplaceVisitor b = new ConreteReplaceVisitor(); A a = new A(b); a.replaceContent(objectsToReplace, "input Word path", "destination path of the updated Word document"); }
Thanks in advance.
Advertisement
Answer
uh… no idea what you’re trying to explain there, or why you’re overcomplicating this (or at least that’s what it seems to me).
This what my docx generators use:
for (XWPFParagraph paragraph : xdoc.getParagraphs()) { // simple run data text replace... for (XWPFRun run : paragraph.getRuns()) { String text = run.getText(0); if (text != null) { for (DOC_FLAGS value : DOC_FLAGS.values()) { if (text.contains(value.name())) { System.out.println(text); System.out.println(value.value); text = text.replace(value.name(), value.value); run.setText(text, 0); } } } } }