6 Replies - 273 Views - Last Post: 14 March 2019 - 08:46 PM

#1 pcaddict   User is offline

  • New D.I.C Head

Reputation: 6
  • View blog
  • Posts: 48
  • Joined: 11-February 09

Need Assistance with Object Model Design for Document Generation

Posted 13 March 2019 - 12:34 PM

I am working on a program that will help myself and co-workers automate and simplify a process we go through to compile various documents into a PDF file for distribution. The pages of this file come from various sources and can be a file ready to be added to the document from disk or a file that I have generated from a template (automated Word/Excel/AutoCAD to pdf within this program). A secondary goal is to be able to save a sort of project file that can be revisited to re-generate this pdf document. My plan for this is to use xml serialization of the "SubmittalPackage" object I create and everything can be restored. This project is going to be done in C#/WPF. The questions I have do not really pertain to the language as much as they do design considerations.

The document I am generating (SubmittalPackage) consists of the following elements:
1. Cover Page (Word document template, populated from xml, converted to pdf in program)
2. Table of Contents (Excel document, populated manually, converted to pdf in program)
3. Tab/Section Separator (Word document template, populated from xml, converted to pdf in program)
4. AutoCAD Drawing (Converted to pdf in program)
5. Data Sheet (PDF stored on disk)

For my object model, specifically related to the layout of the document I know that I need objects to represent a Submittal Package and a Submittal Page.

A SubmittalPackage has properties that will be used to populate information on items 1, 2, and 3 in the list above and has a collection to hold all of the pages in the document. I think an ObservableCollection might be the way to go here since I will be wanting to re-order pages in the collection from a GUI. One thing I have not yet determined is how I want to represent external documents (item 5 above) that will simply be merged into the final document.

So far, my incomplete SubmittalPackage object looks like this:
public class SubmittalPackage
{
	public enum IssuedFor { Approval, Construction, Record };
	public IssuedFor SubmittalIssuedFor
	{ get; set; }

	public ProjectInfo SubmittalProjectInfo
	{ get; set; }
	
	//What to use for pages? ObservableCollection, Dictionary?
}



The SubmittalPage is a whole different beast that has me going back and forth on ways to implement the representation of a page. My current train of thought is that I have a SubmittalPage base class which will then be subclassed for each different type of page (Contents, Cover, Cutsheet, Drawing, Schedule, Stock, Tab), which could be an Enumerable type as seen here and here. Each of the subclasses would then implement any logic required to generate a pdf for that type of page. Each page then gets added to whatever collection is decided in SubmittalPackage. This part of the implementation is where I am stuck. If I go this route each subclass needs to know what the source of data is for that page type and what template file to use. I am also unsure if I am making it too complicated by using subclasses instead of just a flag or enum in the base class but I know WPF binding loves verbosity.

My nowhere near complete SubmittalPage object:
public class SubmittalPage
{
    public UInt16 Index
    { get; set; }

    public string PageDescription
    { get; set; }

    public FileInfo PageFileInfo;

    public PageType SubmittalPageType
    { get; set; }
    
    public enum PageType { Contents, Cover, Cutsheet, Drawing, Schedule, Stock, Tab }
}
public class ContentsPage : SubmittalPage
{}
public class CoverPage : SubmittalPage
{}
public class SchedulePage : SubmittalPage
{}
public class DrawingPage : SubmittalPage
{}
public class TabPage : SubmittalPage
{}



I am also considering the idea of a Tab object that would keep track of all of the pages associated with that section of the overall document. This might complicate the collection used in SubmittalPackage but I am not entirely sure yet.

Looking in from the outside, is there anything obvious that I missed or have not considered?
Should I be considering other options as far as defining a SubmittalPage is concerned? Have I overcomplicated this?

Any feedback is welcome, even the outright trashing of what I have presented here. This has turned into one of the more complex projects I've come up with from an OO perspective and would really appreciate any quideance you have to offer.

Is This A Good Question/Topic? 0
  • +

Replies To: Need Assistance with Object Model Design for Document Generation

#2 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6767
  • View blog
  • Posts: 23,071
  • Joined: 05-May 12

Re: Need Assistance with Object Model Design for Document Generation

Posted 13 March 2019 - 03:48 PM

I'll preface this with I am anti-relational database.

So your construction of:
abstract class BaseClass
{
    public enum ClassType { Concrete1, Concrete2, Concrete3 }

    public abstract ClassType ConcreteType { get; }
}

class Concrete1 : BaseClass
{
    public override ClassType ConcreteType => ClassType.Concrete1;

    public void DoSomethingConcrete1Way()
    {
    }
}

class Concrete2 : BaseClass
{
    public override ClassType ConcreteType => ClassType.Concrete2;

    public void DoSomethingConcrete2Way()
    {
    }
}


class Concrete3 : BaseClass
{
    public override ClassType ConcreteType => ClassType.Concrete3;

    public void DoSomethingConcrete3Way()
    {
    }
}



with the enum is a bad design, because at some point in the future you will be tempted to write code that looks like this:

void DoSomethingBasedOnType(BaseClass obj)
{
    switch (obj.ConcreteType)
    {
    case ClassType.Concrete1:
        var concrete1 = (Concrete1) obj;
        concrete1.DoSomethingConcrete1Way();
        break;

    case ClassType.Concrete2:
        var concrete2 = (Concrete2) obj;
        concrete2.DoSomethingConcrete2Way();
        break;

    case ClassType.Concrete3:
        var concrete3 = (Concrete3) obj;
        concrete3.DoSomethingConcrete3Way();
        break;
    }
}



(Yes, I know that there are some cases when the only true way to implement a factory method for ConcreteX object may require an enum, but let's set aside that discussion for later).

The object oriented way of doing this is to either use the Strategy pattern:
abstract class BaseClass
{
    public abstract void DoSomething();
}

class Concrete1 : BaseClass
{
    public override void DoSomething()
    {
        do something concrete 1 way
    }
}

class Concrete2 : BaseClass
{
    public override void DoSomething()
    {
        do something concrete 2 way
    }
}


class Concrete3 : BaseClass
{
    public override void DoSomething()
    {
        do something concrete 3 way
    }
}

:
:

void DoSomethingBasedOnType(BaseClass obj)
{
    obj.DoSomething();
}



If you don't like the Strategy pattern, the alternative is to use C# 7.x's pattern matching:
abstract class BaseClass
{
}

class Concrete1 : BaseClass
{
    public void DoSomethingConcrete1Way()
    {
    }
}

class Concrete2 : BaseClass
{
    public void DoSomethingConcrete2Way()
    {
    }
}


class Concrete3 : BaseClass
{
    public void DoSomethingConcrete3Way()
    {
    }
}

:
:

void DoSomethingBasedOnType(BaseClass obj)
{
    switch (obj)
    {
    case Concrete1 concrete1:
        concrete1.DoSomethingConcrete1Way();
        break;

    case Concrete2 concrete2:
        concrete2.DoSomethingConcrete2Way();
        break;

    case Concrete3 concrete3:
        concrete3.DoSomethingConcrete3Way();
        break;
    }
}



In general, though, I recommend using the Strategy pattern. Or as Alan Shalloway put it during one of his classes: "If you are switching based on class type, this is a code smell that you should be looking at using the strategy pattern." From my experience, it may alternatively also be an indicator for using the Bridge pattern.

I suspect that the only reason why you really have that enum is for the sake of your RDBMS, where the recommended way to do subclassing is to store an enum as a type id in a column. But if you had an object oriented database, there would be no real need to store that type id explicity, since the OODBMS would take care things transparently for you.
Was This Post Helpful? 0
  • +
  • -

#3 pcaddict   User is offline

  • New D.I.C Head

Reputation: 6
  • View blog
  • Posts: 48
  • Joined: 11-February 09

Re: Need Assistance with Object Model Design for Document Generation

Posted 13 March 2019 - 04:13 PM

Thanks for taking a look Skydiver. The enum is actually only there because I originally thought that might be a way I want to assign an instance some sort of identifier and forgot to take it out when I shifted to the base/subclass design.

I am also database free in this project in the sense that I am only pulling data out that is not driving the construction of my final document. The concept of a SubmittalPage does not depend on a database, rather what type of page I am trying to represent in the application and create for the final document.

I am unfamiliar with the strategy pattern but will look into it.
Was This Post Helpful? 0
  • +
  • -

#4 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6767
  • View blog
  • Posts: 23,071
  • Joined: 05-May 12

Re: Need Assistance with Object Model Design for Document Generation

Posted 14 March 2019 - 12:46 PM

As for your actual SubmittalPackage class, I think that any collection that maintains order and is serializable would work. So yes, the ObservableCollection would likely be a good bet.

Personally, I don't like information/architectures leaking between layers. The object model only really just needs an IEnumerable<SubmissionPage> or at worst an IList<SubmissionPage>. It's when your UI is leaking into the object model where the UI wants to see change notifications, that things start leaking over and requiring that you have an ObservableCollection<SubmissionPage> and for each of your SubmissionPage to implement IChangeNotification.

To get rid of the leaking between the layers, you would have to do a lot of extra typing. Your object model will have the bare necessity to describe itself and what it can do. Instead of just handing over that object model directly to the View, you would wrap each of the object model objects with corresponding view model objects. The view model objects would implement all the notifications, as well as expose ObservableCollection.
Was This Post Helpful? 0
  • +
  • -

#5 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6767
  • View blog
  • Posts: 23,071
  • Joined: 05-May 12

Re: Need Assistance with Object Model Design for Document Generation

Posted 14 March 2019 - 12:53 PM

Slightly off topic, but I am curious: How do you intend to deal with versioning of your various template documents? Let's say a few months from now, you need to add another field like "Reviewed by:" and "Contract Number:". So what happens to your older .XML files which don't have those bits of information and somebody requests documents to be generated?

Or even stranger, but not involving data changes: Let's say you generate documents today using the current templates. Five years from now, your company changes logos and/or company names causing the templates to be updated. So when you generate documents five years from now, but still using your present day .XML file, you'll be generating documents which won't match the original documents that you first produced.
Was This Post Helpful? 0
  • +
  • -

#6 modi123_1   User is online

  • Suitor #2
  • member icon



Reputation: 14854
  • View blog
  • Posts: 59,272
  • Joined: 12-June 08

Re: Need Assistance with Object Model Design for Document Generation

Posted 14 March 2019 - 01:18 PM

View PostSkydiver, on 13 March 2019 - 04:48 PM, said:

I'll preface this with I am anti-relational database.
[...]


*Glares in Klingon*

Posted Image
Was This Post Helpful? 0
  • +
  • -

#7 pcaddict   User is offline

  • New D.I.C Head

Reputation: 6
  • View blog
  • Posts: 48
  • Joined: 11-February 09

Re: Need Assistance with Object Model Design for Document Generation

Posted 14 March 2019 - 08:46 PM

View PostSkydiver, on 14 March 2019 - 03:53 PM, said:

Slightly off topic, but I am curious: How do you intend to deal with versioning of your various template documents? Let's say a few months from now, you need to add another field like "Reviewed by:" and "Contract Number:". So what happens to your older .XML files which don't have those bits of information and somebody requests documents to be generated?

Or even stranger, but not involving data changes: Let's say you generate documents today using the current templates. Five years from now, your company changes logos and/or company names causing the templates to be updated. So when you generate documents five years from now, but still using your present day .XML file, you'll be generating documents which won't match the original documents that you first produced.


I actually hadn't even considered the necessity of template versioning. Now that you mention it though I am re-thinking what properties I really need to be included in the object model. I think I have to limit what I serialize as part of my objects as well as add version attributes to any xml elements that populate a field on a document. The SubmittalPackage object will then have to keep track of what version I am generating. I have not thought it all the way through but this is my first pass at the question you posed.

I am not sure how big of a deal your second point is. If the purpose of the template being modified (logo or whatever) remains the same and keeps the same elements to be replaced then no big deal. The chances of someone going back on to a project and re-generating the documents is incredibly small beyond a period of about 6 months.

Your overall point on how to handle adapting to change without much, if any code modification, is something I have been considering but probably not to the level that I should be. It is funny how originally I was thinking that this would be a relatively straightforward project to undertake and how quickly its complexity has grown.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1