composite class design question

composite class design question

Post by Ed Berose » Wed, 30 Jul 2003 07:22:14



I have a class xfile which represents the data inside a specially
formatted file which comes from another application.  The xfile class is
composed of xheader and xbody classes and includes them.  The xfile
class has a single method by which the data gets populated (by reading
from a file) and a number of different output formats, one or more of
which is chosen at runtime.  My question is about the better way to
design this to avoid an ugly switch.  Here's an extract:

class xfile {
public:
        enum fileFormat { XML, TABULAR, DIAGNOSTIC };
private:
        xheader d_header;
        xbody d_body;
        fileFormat d_outputFormat;
        std::ostream &printToXML(std::ostream &out) const;
        std::ostream &printToTabular(std::ostream &out) const;
        std::ostream &printToDiag(std::ostream &out) const;
public:
        // ...
        fileFormat setOutputFormat(xfile::fileFormat ff);
        std::ostream &printTo(std::ostream &out) const;

Quote:};

std::ostream &operator <<(std::ostream &out, const xfile &xf);

The usage is fairly straightforward:

file.setOutputFormat(xfile::XML);
xmlfile << file;

The ugliness is inside the printTo function implementation:

std::ostream &xfile::printTo(std::ostream &out) const
{
        switch(d_outputFormat)
        {
                case XML:
                        return printToXML(out);
                        break;
                case TABULAR:
                        return printToTabular(out);
                        break;
                case DIAGNOSTIC:
                        return printToDiagnostic(out);
                        break;
                default:
                        return printToXML(out);
        }

Quote:}

Similar ugliness lives within the xheader and xbody classes.

This strikes me as Just Not C++, but I'm unsure of how to do it better.
  I considered virtual xfile functions, but the object must already
exist by the time the output method is chosen and the user may elect to
emit the same data by multiple different formats.  Dubious upcasts as a
cure seem marginally better than the disease of ugly switch statements.

Because what I'd like to do is separate out the output formatting from
the data representation, I was considering making something like an
xOutputAdapter class which would be a virtual base class for the various
output forms, but it was not apparent to me how I could do that without
doing * to my xheader and xbody classes, both of which also have
specific extractors for each file format.

I'd welcome expert advice for how to redesign this more elegantly.

Ed

      [ See http://www.veryComputer.com/]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

composite class design question

Post by Ben Hutching » Thu, 31 Jul 2003 07:20:30



> I have a class xfile which represents the data inside a specially
> formatted file which comes from another application.  The xfile class is
> composed of xheader and xbody classes and includes them.  The xfile
> class has a single method by which the data gets populated (by reading
> from a file) and a number of different output formats, one or more of
> which is chosen at runtime.  My question is about the better way to
> design this to avoid an ugly switch.
<snip>
> Because what I'd like to do is separate out the output formatting from
> the data representation, I was considering making something like an
> xOutputAdapter class which would be a virtual base class

Do you mean abstract base class?

Quote:> for the various output forms, but it was not apparent to me how I could
> do that without doing * to my xheader and xbody classes, both of
> which also have specific extractors for each file format.

I think you will need to change them as well.

Quote:> I'd welcome expert advice for how to redesign this more elegantly.

The Builder pattern might be what you're looking for.  To apply this,
you would define virtual functions in xOutputAdapter that write out the
various parts that must be stored in each file.  xfile, xheader and
xbody would make calls to these.  The xOutputAdapter implementations
would not have any dependency on xfile etc.  However, this pattern is
normally used for constructing complex objects in memory and might not
be suitable for writing files.

In case you don't have access to the Design Patterns book, there are
brief descriptions of the pattern at
<http://www.veryComputer.com/; and
<http://www.veryComputer.com/;.

      [ See http://www.veryComputer.com/]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

composite class design question

Post by Typhoon News Use » Thu, 31 Jul 2003 07:33:58


I would attack this problem with templates, and some simple inheritance.

I would first make xfile a base class:

class xfile_base {
  xheader d_header;
  xbody d_body;

  public:
  /* parameterized tagging */
        struct xml_tag {};
        struct tab_tag {};
        struct diag_tag {};

  /* whatever goes in here */

Quote:};

/**
 parameterize on output format; doesn't need anything.
 */
template<typename OF>
class xfile : public xfile_base { };

/*
 parameterized output type, specialized as necessary
 */
template<typename OF>
std::ostream&
operator<<(std::ostream&,const xfile<OF>&of) {
        // some default??

Quote:}

/* specialized cases */
template<> std::ostream&
operator<<(std::ostream&,const xfile<xml_tag>&of) {
        /* xml output */

Quote:}

template<> std::ostream&
operator<<(std::ostream&,const xfile<tab_tag>&of) {
        /* tab output */

Quote:}

template<> std::ostream&
operator<<(std::ostream&,const xfile<diag_tag>&of) {
        /* diag output */

Quote:}

Now, there are some wonderful advantages to this if you are using the STL. If
not, it's still pretty neat. You would have to parameterize the xheader and
xbody classes in the same way. As a compile-time distinction, this will have,
in most cases, performance advantages over run-time selection.

Where before you would select a format, you can now simply cast your output,
and the templated ostream will be selected accordingly.

For example, where before you had

Quote:> file.setOutputFormat(xfile::XML);
> xmlfile << file;

You would now have:
 xmlfile << static_cast<xfile<xml_tag> >(file);

You can do similar things in the STL, for outputting many files, given a
 std::list<xfile> list_xf, list of xfile objects:

std::copy(list_xf.begin(), list_xf.end(),
        std::ostream_iterator<xfile<xml_tag> >(xmlfile));

Which should output all the xfile objects in the list_xf list in xml format
using the << operator for xfile<xml_tag>. (I'm quite certain that this cast
will work; alternatively you can use std::transform, but that copies the
object, and is hence slightly less desirable, from a performance point of
view)

Hope that helps!

Cheers,
Brian


Quote:> I have a class xfile which represents the data inside a specially
> formatted file which comes from another application.  The xfile class is
> composed of xheader and xbody classes and includes them.  The xfile
> class has a single method by which the data gets populated (by reading
> from a file) and a number of different output formats, one or more of
> which is chosen at runtime.  My question is about the better way to
> design this to avoid an ugly switch.  Here's an extract:

> class xfile {
> public:
> enum fileFormat { XML, TABULAR, DIAGNOSTIC };
> private:
> xheader d_header;
> xbody d_body;
> fileFormat d_outputFormat;
> std::ostream &printToXML(std::ostream &out) const;
> std::ostream &printToTabular(std::ostream &out) const;
> std::ostream &printToDiag(std::ostream &out) const;
> public:
> // ...
> fileFormat setOutputFormat(xfile::fileFormat ff);
> std::ostream &printTo(std::ostream &out) const;
> };

> std::ostream &operator <<(std::ostream &out, const xfile &xf);

> The usage is fairly straightforward:

> file.setOutputFormat(xfile::XML);
> xmlfile << file;

> The ugliness is inside the printTo function implementation:

> std::ostream &xfile::printTo(std::ostream &out) const
> {
> switch(d_outputFormat)
> {
> case XML:
> return printToXML(out);
> break;
> case TABULAR:
> return printToTabular(out);
> break;
> case DIAGNOSTIC:
> return printToDiagnostic(out);
> break;
> default:
> return printToXML(out);
> }
> }

> Similar ugliness lives within the xheader and xbody classes.

> This strikes me as Just Not C++, but I'm unsure of how to do it better.
>   I considered virtual xfile functions, but the object must already
> exist by the time the output method is chosen and the user may elect to
> emit the same data by multiple different formats.  Dubious upcasts as a
> cure seem marginally better than the disease of ugly switch statements.

> Because what I'd like to do is separate out the output formatting from
> the data representation, I was considering making something like an
> xOutputAdapter class which would be a virtual base class for the various
> output forms, but it was not apparent to me how I could do that without
> doing * to my xheader and xbody classes, both of which also have
> specific extractors for each file format.

> I'd welcome expert advice for how to redesign this more elegantly.

> Ed

      [ See http://www.veryComputer.com/]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
 
 
 

composite class design question

Post by johnc » Thu, 31 Jul 2003 17:19:11



 > I have a class xfile which represents the data inside a specially
 > formatted file which comes from another application.  The xfile class is
 > composed of xheader and xbody classes and includes them.  The xfile
 > class has a single method by which the data gets populated (by reading
 > from a file) and a number of different output formats, one or more of
 > which is chosen at runtime.  My question is about the better way to
 > design this to avoid an ugly switch.  Here's an extract:
 >
 > class xfile {
 > public:
 >       enum fileFormat { XML, TABULAR, DIAGNOSTIC };
 > private:
 >       xheader d_header;
 >       xbody d_body;
 >       fileFormat d_outputFormat;
 >       std::ostream &printToXML(std::ostream &out) const;
 >       std::ostream &printToTabular(std::ostream &out) const;
 >       std::ostream &printToDiag(std::ostream &out) const;
 > public:
 >       // ...
 >       fileFormat setOutputFormat(xfile::fileFormat ff);
 >       std::ostream &printTo(std::ostream &out) const;
 > };
 >
 > std::ostream &operator <<(std::ostream &out, const xfile &xf);
 >

[snip]

 > I'd welcome expert advice for how to redesign this more elegantly.

Without claiming any particular expertise, I can suggest an approach
you might want to try out.  ;-)

Define a set of lightweight wrapper classes around a std::ostream, one
for each output format (e.g. class XMLFormat, class TabularFormat,
etc.).  All they need to do is hold a reference or pointer to the
std::ostream and hand it to the caller upon request.

Then define the printTo member funtion to take one of the wrapper
classes as its parameter (instead of std::ostream).  Provide an
overload for each wrapper class.  Internally, these functions would
look just like the private format-specific members you already have
(except that they'd obtain the ostream& from the wrapper object rather
than directly as a function param).

Finally, you'll want to define the necessary operator<<() functions.
You can provide operator<< as a member in each wrapper class, or you
can write a separate one (as a free function) for each wrapper class,
or you can write it as a template.

Here's an example of this approach:

#include <ostream>

class XMLFile_t {
    public:
       explicit XMLFile_t(std::ostream& os): mpStream (&os) {}

       std::ostream& GetStream() const {return *mpStream;}

    private:
       std::ostream* mpStream;

Quote:};

XMLFile_t
XMLFile(std::ostream& os) { return XMLFile_t(os); }

class TextFile_t {
    public:
       explicit TextFile_t(std::ostream& os): mpStream(&os) {}

       std::ostream& GetStream() const {return *mpStream;}

    private:
       std::ostream* mpStream;

Quote:};

TextFile_t
TextFile(std::ostream& os) { return TextFile_t(os); }

class DataObject {
    public:
       const XMLFile_t&
       PrintTo(const XMLFile_t& f) const {
          f.GetStream() << "<XML> I'm printing XML! </XML>";
          return f;
       }
       const TextFile_t&
       PrintTo(const TextFile_t& f) const {
          f.GetStream() << "I'm printing text!";
          return f;
       }
       template <class T>
       friend
       T
       operator<<(T out, const DataObject& data) {
          return data.PrintTo(out);
       }

Quote:};

#include <iostream>

int main() {
    DataObject data;
    XMLFile(std::cout) << data;
    std::cout << '\n';
    TextFile(std::cout) << data;
    std::cout << std::endl;

Quote:}

The helper functions XMLFile() and TextFile() are more or less
syntactic sugar.  Some compilers (e.g. gcc) won't let you write:

   XMLFile_t (std::cout) << data;

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

composite class design question

Post by Jon Hein » Thu, 31 Jul 2003 17:25:11


When I encounter a large switch statement, the solution that generally
occurs to me is to use either pointers to functions or functors.

In this case, each of your print functions has the same signature. As
a result, the setOutputFormat() method could remap a pointer to the
appropriate function. In general, remember that virtual functions are
( generally ) implemented as a table of pointers to functions that get
remapped appropriately. There's nothing that says you can't take the
same approach without actually creating additional classes and
inheritance.

However, if you feel like being more OO about things, you could write
a functor to represent the "action of printing". You would create
three ( or more ) classes such as:

class XMLPrinter : public Printer
{
public:
    virtual std::ostream &operator () ( std::ostream& out, const xfile
&xf );

Quote:};

and switch the functor in setOutputFormat(). You could make a base
Printer class as indicated above so that in your class, you have a
pointer to a Printer object.

I don't believe there is anything "un-C++" about switch statements. In
this case, unless you _realistically_ think this code will be re-used
somewhere else, or you plan on having an unmanageably large switch
statement, you probably need not change anything.

For example, I once wrote a UI that had a huge nested switch
statements for any of 100+ button ids that would each do different
things based upon a state elsewhere. It eventually became unweildy and
I considered reworking it to use pointers to functions or functors (
actions ). However, the implementation was simple and straightforward,
and debugging it was simple. Don't go overboard with your OO tendency.
C++ gracefully supports multiple coding styles, including but not
limited to OO. If you were doing Java, I would say otherwise, but this
is a C++ forum. ;)

regards,
jon

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

composite class design question

Post by ka.. » Sat, 02 Aug 2003 03:55:48



Quote:> When I encounter a large switch statement, the solution that generally
> occurs to me is to use either pointers to functions or functors.
> In this case, each of your print functions has the same signature. As
> a result, the setOutputFormat() method could remap a pointer to the
> appropriate function. In general, remember that virtual functions are
> ( generally ) implemented as a table of pointers to functions that get
> remapped appropriately. There's nothing that says you can't take the
> same approach without actually creating additional classes and
> inheritance.
> However, if you feel like being more OO about things, you could write
> a functor to represent the "action of printing". You would create
> three ( or more ) classes such as:
> class XMLPrinter : public Printer
> {
> public:
>     virtual std::ostream &operator () ( std::ostream& out, const xfile
> &xf );
> };
> and switch the functor in setOutputFormat(). You could make a base
> Printer class as indicated above so that in your class, you have a
> pointer to a Printer object.

My preference would be to have a getOutputFormatter() function which
returned the correct pointer to function or pointer to functor.

Quote:> I don't believe there is anything "un-C++" about switch statements.

It depends on what you are doing.  Part of the problem is that they can
be used to confond the what and the how aspects -- in this case, for
example, the selection logic and the logic in the individual formatting
functions.  Using a switch in the implementation of getOutputFormatter()
seems perfectly reasonable, although it is worth considering the
alternatives as well: a std::map, and if the integral values form a
densly populated subrange, a simple table.  The advantage of an std::map
is that if you later expand the indentifiers to be a more complex type,
you don't have to change the basic logic; but if the basic logic is
encapsulated in setOutputFormat anyway, it's no big deal.

--

Conseils en informatique oriente objet/     http://www.gabi-soft.fr
                    Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

composite class design question

Post by Siemel Nara » Sun, 03 Aug 2003 02:18:06



> class XMLPrinter : public Printer
> {
> public:
>     virtual std::ostream &operator () ( std::ostream& out, const xfile
> &xf );
> };

> and switch the functor in setOutputFormat(). You could make a base
> Printer class as indicated above so that in your class, you have a
> pointer to a Printer object.

You could go all the way with the factory pattern.  Make a registry class
that holds a map string to function pointer, where the string represents the
file extension (xml, txt, ...) and the function pointer represents the
function that creates a new printer for that extension.  Your registry class
may have a function to iterate through all the extensions so you can display
all supported file formats in the FileOpen and FileSaveAs picklist.

Quote:> I don't believe there is anything "un-C++" about switch statements. In
> this case, unless you _realistically_ think this code will be re-used
> somewhere else, or you plan on having an unmanageably large switch
> statement, you probably need not change anything.

Yes, I use switch-case a bit myself.  It's generally the first approach to
cross my mind.  It's nice that the function bodies after the case statements
can access the local variables of the function.  Then again, with the
callback functor object way you create a single struct or class that holds
all the variables (or member functions to access these variables) and pass a
reference to that struct to the callback.  In the switch-case approach you
can write two case statements one after the other without a break statement
between them.  Then again, with the functor approach the derived class
function can call the base class function.

But the functor way is still more extensible.  And forces you to think about
parameters to pass to the callback so forces a more rigid structure on your
code, which has its advantages and disadvantages.

--
+++++++++++
Siemel Naran

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

 
 
 

1. Design Question: Hierarchical Structures (Composite?)

I'm designing a system that allows managers to recommend salary
increases for their employees and I've come across a hurdle that I was
hoping someone here could help me with.  My question is are there any
well known patterns that address the situation below?

The system is a web-based Java/JSP/Oracle application that allows
managers to recommend salary increases for people that report directly
to them.  The salary increases must then be approved by higher levels of
management.  The basic structure I came up with looks like this:

Employee ---------> SalaryRecommendation

What I'm having trouble with is that there are many situations where
these salary recommendations must be summed up for reports to upper
management.  Sometimes the summation is only one level deep while other
times it must be summed across the entire depth of the "tree" of employees.

My basic approach was to have a Manager class (which inherits from
Employee) that has a directReports() method that returns the group of
employees that report directly to that manager.  I figured using this
method would allow any client to retrieve the entire structure by
recursively calling directReports() until they reach the lowest level.

The problem is that this recursive descent must be repeated by many
Servlets and JSP pages, so I would like to encapsulate the process.  I
thought about using the Composite pattern, like so:

Employee ----------> SalaryRecommendation

EmployeeGroup -----> CompositeSalaryRecommendation

Where EmployeeGroup inherits from, say, ArrayList and provides
additional features, and CompositeSalaryRecommendation does the
summation of the salary recommendations for that group of employees.

However, I'm not sure that this is a valid use of the Composite pattern,
and also that it does not address the "one level" vs. "entire tree"
situation I mentioned above.

I'm sorry for the long post, but I'm kind of stuck on this one.  Does
anyone have any advice?

Thanks!
--
Jason Voegele
"We believe that we invent symbols. The truth is that they invent us."
     -- Gene Wolfe, The Book of the New Sun

2. W2K Laptop features...

3. ComboBox-ActiveX is in design-mode on ATL composite control

4. EOR marker in text files.

5. Composite Design Pattern - An Issue

6. how to create a chain assembly?

7. Composite classes and Category Theory

8. HUNTING DIALER

9. Class design question

10. Date Class - Design question

11. some class hierarchy design questions

12. Simple Class Design Question

13. class design question