I had the same case to solve and I finaly used a bridge design pattern separating the receipt and his content from the printing.
abstract class Receipt{
private Printer printer;
public Receipt (Printer printer){
if (printer==null){
throw new NullArgumentException ("Printer can't be null.");
}
this.printer=printer;
}
public abstract PrintJobStatus printReceipt ();
}
abstract class Printer {
public abstract void printLine (String txt, Alignement al, Font fo, Size si);
public abstract void printQrCode(String qrCodeStr, QrType qrType, Size si);
}
public class VatReceipt extend Receipt{
public VatReceipt (Printer printer){
super (printer);
}
@Overide
public PrintJobStatus printReceipt ()
PrintJobStatus result=PrintJobStatus.UNDEFINE;
printer.printLine ("Hello i'm the receipt.header",
Alignement.CENTER, Font.A, Size.SMALL);
...
...
return result;
}
public class EpsonT88Printer extend Printer{
private EpsonPrinterSdk epsonSdkPrinter;
@Overide
public void printLine(String txt, Alignement al, Font fo, Size si){
int epsonAlignement=convertGenericAligToEpsonAlig(al);
int epsonFont=convertGenericFontToEpsonFont(fo);
...
epsonSdkPrinter.printTextLine (txt, epsonAlignement,...);
}
}
I'm answering from my phone...