1

I've been building an application that processes documents through different filters.

I have a class (or better as an interface for creating test-doubles?) called Document. The Document class contains many fields and therefore I was thinking about using the Builder pattern for construction.

Now, there are certain "specialized" documents that contain additional fields (let's call it SpecialDocument). The obvious solution would be to extend the Document class. However, how would I then (during runtime) take a Document instance and make it a SpecialDocument instance? Remember that the construction of the Document instance is quite complex, therefore I think, a copy-constructor is too tedious and error-prone (when adding a filed etc.).

Another solution that I can think of is to pass the original Document instance to the SpecialDocument constructor and then delegate all document calls to that instance.

Or should I maybe just add those fields from SpecialDocumentto the Document class and then provide optional getters, like so Optional<String> getSpecialField? This last option seems to be the least preferable since it mixes concepts and the client would never be sure about the type of document it is dealing with (besides having to deal with the optional first).

Is there a simpler and more elegant way to model this scenario?

Thank you very much for you advice.

2

2 Answers 2

6

The class of an object is not supposed to change during the object life-cycle. If you think it should, there must be something wrong in the design.

The kind of challenge that you describe is usually addressed with:

  • the decorator pattern: a decorator SpecialDocument would add some responsibilities to the base class Document, such as some more methods, or some more properties, or both together.
  • the entity component system: an entity Document would have some components such as SpecialDocument, which would define a set of properties and behaviors.
  • a higher level of abstraction: Document would be defined in such a way that a strategy could e set dynalically to alter its behavior.

The common denominator behind these design patterns is the creative use of composition that is preferred over inheritance whenever the thought of changin class dynamically crosses your mind.

1

Most often I'd do this:

class SpecialDocument {
    Document getDocument();
    String getField1();
    String getField2();
}

The SpecialDocument doesn't extend Document, instead it contains a reference to a Document which is returned upon request.

  1. This avoids creating a complex copy constructor
  2. This avoids creating a bunch of delegation methods
  3. This allows a function to explicitly take either a Document or SpecialDocument depending on what the function needs.

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.