4
\$\begingroup\$

Following is a chunk of code from my class which generates PDF documents. I am refactoring my code and in the process I have created short methods. But I have to pass 'table i.e PdfPTable' to my methods again and again. How can I avoid this?

PdfPTable orgTable = new PdfPTable(2);
PdfPCell cell = null;
string orgName = dr["OrganizationName"].ToString();
cell = new PdfPCell(new Phrase(orgName, Heading1)) {Colspan = 2, BackgroundColor = BckColor, HorizontalAlignment = Element.ALIGN_CENTER };
orgTable.AddCell(cell);

AddOrganizationProfile(document, dr, orgTable);
OrganizationHeadOffice(document, dr, orgTable);
OrganizationContacts(document, orgTable, orgId);

private void OrganizationHeadOffice(Document document, DataRow dr, PdfPTable table)
{
    AddTitle("Office Contact & Information:", table);

    // How to avoid passing table variable again and again here.
    AddLegend("Address:", table);
    AddDataValue(dr["address"].ToString(), table);
    AddLegend("Contact Number:", table);
    AddDataValue(phone1, table);
}

private void AddTitle(string title, PdfPTable table)
{
    table.AddCell(new PdfPCell(new Phrase(title, TableFontCaption)) { Colspan = 2, BackgroundColor = BckColor });
}

private void AddLegend(string legend, PdfPTable table)
{
    table.AddCell(new PdfPCell() { Border = Rectangle.NO_BORDER, Phrase = new Phrase(legend, TableFontCaption) });
}

private void AddDataValue(string dataValue, PdfPTable table)
{
    table.AddCell(new PdfPCell() { Border = Rectangle.NO_BORDER, Phrase = new Phrase(dataValue, TableFont) });
}
\$\endgroup\$

5 Answers 5

5
\$\begingroup\$

Make PdfPTable a property of the class and set it in the constructor.

\$\endgroup\$
4
\$\begingroup\$

This looks like a good candidate for the Builder pattern.

You have a PdfPTableBuilder class, whose sole responsibility is to (of course) build a PdfPTable instance. You initialize it and call various setter methods, and each method returns this, so that you can chain them:

PdfPTableBuilder builder = new PdfPTableBuilder();
builder.AddLegend("Address:").AddDataValue(dr["address"].ToString());
// etc.
return builder.build();

The builder itself simply holds all the data it needs to construct the table instance, and pours that into the table in the build method.

\$\endgroup\$
0
2
\$\begingroup\$

Another option which has not yet been covered would be extension methods.

If the code inside your methods is not specific to the class that is calling it, by which I mean if the AddTitle method would be exactly the same regardless of which class wanted to create a PDF, you could make it an extension method by moving it to a static class

public static class PdfPTableExtensions
{
    public static void AddTitle(this PdfPTable table, string title)
    {
        table.AddCell(new PdfPCell(new Phrase(title, TableFontCaption)) { Colspan = 2, BackgroundColor = BckColor });
    }
}

which you can then call as follows:

table.AddTitle("Office Contact & Information:");
\$\endgroup\$
1
\$\begingroup\$

Your methods, as they stand, appear to be able to be static. In other words, there is no reliance on class state at all. Make orgTable a member of the class and have each method access it as this.orgTable rather than as a method parameter.

\$\endgroup\$
0
\$\begingroup\$

Expanding on the answer from @CarlManaster:

You can have your "builder" extend IEnumerable, then add an Add(PdfTableItemType cellType, string content) method, and then add items using the collection initializer.

Sample usage

public static PdfPTable ReticulateSplines() {
    PdfPTableBuilder builder = new PdfPTableBuilder() {
        { PdfTableItemType.Title, "Office Contact & Information:" },
        { PdfTableItemType.Legend, "Address:" },
        // ...
    };
    // Or, if you prefer:
    builder.Add(PdfTableItemType.DataValue, "address".ToString());
    // etc.
    //return builder.Build();
}

Example skeleton for the builder

public class PdfPTableBuilder : IEnumerable
{
    public enum PdfTableItemType
    {
        Title,
        Legend,
        DataValue,
    }

    public IEnumerator GetEnumerator() {
        throw new NotImplementedException();
    }

    public void Add(PdfTableItemType cellType, string content) {
        switch (cellType) {
            case PdfTableItemType.Title:
                // table.AddCell(...);
                break;
            // etc;
        }
    }

    public PdfTable Build() {
        throw new NotImplementedException();
    }
    public class PdfTable { } // Dummy.
}
\$\endgroup\$
4
  • \$\begingroup\$ The idea of using an enum and a switch doesn't make it very extensible as any time you want to add a new type you need to modify the enum and the class. Also, I fail to see what the point of the builder implementing IEnumerable is? \$\endgroup\$ Commented Oct 5, 2012 at 17:37
  • \$\begingroup\$ @TrevorPilley 1. the point of extending IEnumerable it to allow using the collection initializer syntax. Do you think this is convoluted? 2. Where did extensibility come into the picture? In any case, any time you want to add a new type [of cell] you would have to write somewhere the code for writing that type of cells. I don't see how having that code in a new switch case is any worse than having it in a new method. \$\endgroup\$
    – ANeves
    Commented Oct 5, 2012 at 19:10
  • 1
    \$\begingroup\$ The reason is that it breaks OCP (Open Closed Principle), if you wanted to add another type of cell and you had a method per cell type, you could subclass the original class to add functionality without having to change the original implementation. Ok, I understand what you mean now re: implementing IEnumerable - however I think you are misusing it since you are not actually able to enumerate the class. It would probably be better to add a constructor which accepts the initial items in an IEnumerable of KeyValuePairs if you insist on the enum. \$\endgroup\$ Commented Oct 6, 2012 at 11:47
  • \$\begingroup\$ I understand. Very good points. \$\endgroup\$
    – ANeves
    Commented Oct 8, 2012 at 12:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.