1
\$\begingroup\$

I would like to create a generic template class for my document processor. Assuming the template has a source file path and a "content", here's what I came up with:

Template

public interface ITemplate<T>
{
    /// <summary>
    /// The filepath of the base document for the template.
    /// </summary>
    String BaseDocumentFilePath { get; }

    /// <summary>
    /// Retrieve the underlying template source.
    /// </summary>
    /// <returns>T</returns>
    T GetContent();
}
public class WordTemplate : ITemplate<XmlDocument>
{
    private string _baseDocumentFilePath;
    private XmlDocument _content;

    public WordTemplate(XmlDocument content, string baseDocumentFilepath)
    {
        _content = content;
        _baseDocumentFilePath = baseDocumentFilepath;
    }

    public string BaseDocumentFilePath { get { return _baseDocumentFilePath;}}

    public XmlDocument GetContent()
    {
        return _content;
    }
}

Ex Doc Generator

public interface IDocumentGenerator
{
    /// <summary>
    /// Generates a document from an instance of <see cref="ITemplate"/>. 
    /// </summary>
    /// <param name="template">The template for the document.</param>
    /// <param name="outputDocumentFilepath">The full file path of the result output.</param>
    /// <returns>Returns filepath for generated document.</returns>
    void Generate<T>(ITemplate<T> template, string outputDocumentFilepath);
}

public class WordDocumentGenerator : IDocumentGenerator
{
    public void Generate<T>(ITemplate<T> template, string outputDocumentFilepath)
    {
        XmlDocument xmlDocumentBody = template.GetContent() as XmlDocument;

        // generate doc
    }
}

The template would be created elsewhere and injected into the document generator. My question is, is this a good design? I am casting the generic T into XmlDocument (which is what I need for that specific implementation) and I don't think that's the right way to use generics. I've always been a little lost when it comes to generics.

\$\endgroup\$
2
  • \$\begingroup\$ You simply can't do template.GetContent() as XmlDocument unless T is XmlDocument. You need some sort of Func<T, XmlDocument> to make this work. Any why are you working with the old XmlDocument and not the newer XDocument? \$\endgroup\$ Commented Feb 11, 2015 at 1:41
  • \$\begingroup\$ I have finished implementing this...I removed the //generate doc portion for simplicity. If this isn't the place for design review, where is the proper place? \$\endgroup\$
    – Cody
    Commented Feb 11, 2015 at 3:16

1 Answer 1

2
\$\begingroup\$

The template related class and interface are looking good to me. But the generator related class and interface are flawed.

Assume one would call the Generate() method with an ITemplate<string> which would be totally legal. Sure it would work, but xmlDocumentBody would be null.

You could if the passed in template isn't a ITemplate<XmlDocument> throw some exception, but a user of this class wouldn't expect for a generic class which is called correctly to get an exception.

So you should better make the IDocumentGenerator generic and not the Generate() method.

public interface IDocumentGenerator<T>
{
    void Generate(ITemplate<T> template, string outputDocumentFilepath);
}

and now your WordDocumentGenerator class should implement IDocumentGenerator<XmlDocument> like

public class WordDocumentGenerator : IDocumentGenerator<XmlDocument>
{
    public void Generate<T>(ITemplate<XmlDocument> template, string outputDocumentFilepath)
    {
        XmlDocument xmlDocumentBody = template.GetContent();

        // generate doc
    }
}

For sure if you have different types of templates you should add a DocumentGeneratorFactory which returns the desired DocumentGenerator for the task at hand.

\$\endgroup\$

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.