39253

Correct OOP Practice for class properties tied by logic

Question:

I have a class called 'documentsection' which defines part of a document that later gets assembled in HTML. There are properties within it, and which values are required (or valid) depend on one another. For example:

a) There is an enumeration called 'section type' which can be 'view' (in this case, another property called 'content' contains the path/filename of a file to read in). Or it can be 'text' where the 'content' property text is itself placed in the document.

b) There is another enumeration called 'Action' which can be of type 'append', 'prepend' or 'replacebytag'. In the last case, another property becomes relevant, called 'tagtoreplace'. If we are appending/prepending, this tagtoreplace property can be empty.

What is the best practice way to represent such interdependencies? There are several ways I can think of, none of which reek with beauty:

<ul><li>

When the method to 'generate the document' is called, go through the properties to ensure they conform to this logic.

</li> <li>

Put checks in the get/set methods. One issue with this is that when I set my section type to 'view' I may not set my 'content' property until a line or so afterwards - so you can't reject the request to set it at that point.

</li> <li>

Use separate properties somehow to partition the uses - eg 'content' in my first example above shouldn't be used for a filepath in one case and a bunch of HTML content in another. This doesn't smell right to me, but having separate properties for each seems excessive.

</li> <li>

Inherit subclasses, each with different sets of the additional needed properties. Since there can be various combinations of section type and action type, I can't think of an elegant way to bake all this logic into such a structure. But I'm no OOP guru!

</li> </ul>

Any thoughts on the best approach?

Thanks!

Answer1:

I would go with the following approach:

interface ISection { void Render(); // or String Render() if you want to return a string } class ViewSection : ISection { public String Filename { get; set; } public void Render() { // do stuff with Filename and/or return the content of the file } } class TextSection : ISection { public String Text { get; set; } public void Render() { // do stuff with Text and/or return it } } class DocumentSection { ISection _section; public void Render() { _section.Render(); } }

You can then easily create new classes implementing ISection that supply additional Sections. Same goes for the "actions", define an IAction interface with a kind of Render or PerformAction method which you call.

Answer2:

Setting a property shouldn't have side effects on other properties.

If you are to do something like that you should use a method to set everything at once.

Answer3:

I would separate HTML generation from the document generation itself. Have classes used to define a document and then have other classes used to generate each section of a document. By doing so you can easily add new formats later on (or more easily either test document building or html generation)

<blockquote>

a) There is an enumeration called 'section type' which can be 'view' (in this case, another property called 'content' contains the path/filename of a file to read in). Or it can be 'text' where the 'content' property text is itself placed in the document.

</blockquote>

Type properties are usually a design smell. Have a Section class which you derive for each type of section. Then just add the correct derived class.

<blockquote>

b) There is another enumeration called 'Action' which can be of type 'append', 'prepend' or 'replacebytag'. In the last case, another property becomes relevant, called 'tagtoreplace'. If we are appending/prepending, this tagtoreplace property can be empty.

</blockquote>

I'm not clear with how you use the action property.

Answer4:

If a property is meant for a filepath, then that's what it is meant for. If it is meant for content, that is what it is meant for. When one property can represent two different things, confusion and errors are bound to occur.

I think you need subclasses. Take a look at the <a href="http://www.dofactory.com/Patterns/PatternAbstract.aspx" rel="nofollow">abstract factory pattern</a> as a way to manage the creation of the classes.

Recommend

  • Image is not displayed when parent image is clicked
  • Vertical buttons with equal width
  • Teracotta and Hibernate Search
  • Re-implementing lists with closures in scheme
  • Cast While Looping Over Dictionary in Swift
  • CSS overflow with long URL
  • How do I use Java generic wildcards with methods taking more than one generic parameter?
  • How to count amount of elements in a row of a matrix in C
  • How do I include screenshots of the full page in my serenity report (and not only of the viewport) u
  • Allocating a 2D contiguous array within a function
  • Refactoring advice: maps to POJOs
  • Are there any side effects from calling SQLAlchemy flush() within code?
  • Activation Function choice for Neural network
  • XSLT foreach repeating nodes to flat
  • Does Apple allow the usage of sysctl.h within iOS applications?
  • Android Studio Can't Find tools.jar
  • UWP/C# - Issue with AQS and USB Devices
  • SetWindowsHookEx does not react on media keys
  • RxJava debounce by arbitrary value
  • How to add git credentials to the build so it would be able to be used within a shell code?
  • Assign variable to the value in HTML
  • onBackPressed() not being executed
  • Ensure fsync did its job
  • Jackson Parser: ignore deserializing for type mismatch
  • How to use remove-erase idiom for removing empty vectors in a vector?
  • Java: can you cast Class into a specific interface?
  • Repeat a vertical line on every page in Report Builder / SSRS
  • Why is an OPTIONS request sent to the server?
  • AES padding and writing the ciphertext to a disk file
  • How to add a column to a Pandas dataframe made of arrays of the n-preceding values of another column
  • Updating server-side rendering client-side
  • How to extract text from Word files using C#?
  • Trying to switch camera back to front but getting exception
  • ActionScript 2 vs ActionScript 3 performance
  • SQL merge duplicate rows and join values that are different
  • Free memory of cv::Mat loaded using FileStorage API
  • Angular 2 constructor injection vs direct access
  • Why joiner is not used after Sequence generator or Update statergy
  • Programmatically clearing map cache
  • Android Heatmap on canvas or ImageView