Creating and Maintaing Heavy and Light Versions of Classes

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jack

    Creating and Maintaing Heavy and Light Versions of Classes

    Hello

    I have a library of calculationally intensive classes that is used both by a
    GUI based authoring application and by a simpler non-interactive rendering
    application. Both of these applications need to serialise the classes
    to/from the same files but only the GUI app needs the full range of class
    methods.

    Now, the rendering app needs to be ported to multiple OS's but the GUI
    doesn't. In order to reduce the time/cost of porting I'd like to create two
    versions of the classes - one that only contains the data plus minimum
    methods (mostly copy-construct plus serialisation and a few others) and one
    with the full range of methods.

    My initial thought was to define the simple classes as bases classes and
    then derive the full classes from these. However, some of the base classes
    would contain members which are themselves classes which need to be
    simplified and if I converted these to the simpler classes then it's not
    clear how I could recover the full functionality in the derived versions of
    these. Hope that makes sense ;-)

    Does anyone have any suggestions about how to handle this problem - would
    templates be a way around, or maybe smart pointers?

    Thanks
    Jack



  • Derek

    #2
    Re: Creating and Maintaing Heavy and Light Versions of Classes

    "Jack" wrote...[color=blue]
    > Hello
    >
    > I have a library of calculationally intensive
    > classes that is used both by a GUI based authoring
    > application and by a simpler non-interactive
    > rendering application. Both of these applications
    > need to serialise the classes to/from the same files
    > but only the GUI app needs the full range of class
    > methods.
    >
    > Now, the rendering app needs to be ported to multiple
    > OS's but the GUI doesn't. In order to reduce the
    > time/cost of porting I'd like to create two versions
    > of the classes - one that only contains the data
    > plus minimum methods (mostly copy-construct plus
    > serialisation and a few others) and one with the full
    > range of methods.
    >
    > My initial thought was to define the simple classes
    > as bases classes and then derive the full classes
    > from these. However, some of the base classes would
    > contain members which are themselves classes which
    > need to be simplified and if I converted these
    > to the simpler classes then it's not clear how I
    > could recover the full functionality in the derived
    > versions of these. Hope that makes sense ;-)
    >
    > Does anyone have any suggestions about how to handle
    > this problem - would templates be a way around, or
    > maybe smart pointers?
    >
    > Thanks Jack[/color]

    It's hard to make a recommendation without more information, but I
    don't think memory management is at the heart of your difficulties, so
    I don't see how smart pointers help. Templates might be useful, but
    it's hard to say without knowing the details of your classes.

    I would just create two independent classes:

    struct LightWidget { /*...*/ };

    struct Widget
    {
    explicit Widget(const LightWidget&) { /*...*/ }
    };

    Use LightWidget when it's all you need (rendering) and create a full
    Widget when you have to (GUI). Widget can either be initialized from
    data in LightWidget or -- if your design permits -- Widget can store a
    LightWidget object and build functionality on top of it, perhaps just
    forwarding some common operations (like serialization).


    Comment

    • Jack

      #3
      Re: Creating and Maintaing Heavy and Light Versions of Classes


      "Derek" <none@none.co m> wrote in message
      news:bthqgs$7hs 0l$1@ID-46268.news.uni-berlin.de...[color=blue]
      >
      > It's hard to make a recommendation without more information, but I
      > don't think memory management is at the heart of your difficulties, so
      > I don't see how smart pointers help. Templates might be useful, but
      > it's hard to say without knowing the details of your classes.
      >
      > I would just create two independent classes:
      >
      > struct LightWidget { /*...*/ };
      >
      > struct Widget
      > {
      > explicit Widget(const LightWidget&) { /*...*/ }
      > };
      >
      > Use LightWidget when it's all you need (rendering) and create a full
      > Widget when you have to (GUI). Widget can either be initialized from
      > data in LightWidget or -- if your design permits -- Widget can store a
      > LightWidget object and build functionality on top of it, perhaps just
      > forwarding some common operations (like serialization).
      >[/color]

      Thanks for taking the time...

      The problem I have is that Widget itself contains a member of type SubWidget
      which also needs to have a LightSubWidget counterpart. So the question is
      how to create the Widget/SubWidget object from the
      LightWidget/LightSubWidget object - in a way which is reliable and easy to
      maintain.

      So far the only simple way I can think of achieving this is to bracket all
      the heavy code within #ifdefs and set a compiler directive appropriately. It
      would be nice if there were some better mechanism for maintaining two
      related sets of objects (in separate source files). But is there?

      Thanks
      Jack


      Comment

      • Robert Frunzke

        #4
        Re: Creating and Maintaing Heavy and Light Versions of Classes


        Jack wrote:
        ....[color=blue]
        > Now, the rendering app needs to be ported to multiple OS's but the GUI
        > doesn't. In order to reduce the time/cost of porting I'd like to create two
        > versions of the classes - one that only contains the data plus minimum
        > methods (mostly copy-construct plus serialisation and a few others) and one
        > with the full range of methods.[/color]
        ....

        Why not separate the GUI completely from your "data" classes ?



        Robert

        Comment

        • Derek

          #5
          Re: Creating and Maintaing Heavy and Light Versions of Classes

          > "Jack" wrote:[color=blue]
          >[color=green]
          > > It's hard to make a recommendation without more
          > > information, but I don't think memory management is at
          > > the heart of your difficulties, so I don't see how smart
          > > pointers help. Templates might be useful, but it's hard
          > > to say without knowing the details of your classes.
          > >
          > > struct LightWidget { /*...*/ };
          > >
          > > struct Widget
          > > {
          > > explicit Widget(const LightWidget&) { /*...*/ }
          > > };
          > >
          > > Use LightWidget when it's all you need (rendering) and
          > > create a full Widget when you have to (GUI). Widget can
          > > either be initialized from data in LightWidget or -- if
          > > your design permits -- Widget can store a LightWidget
          > > object and build functionality on top of it, perhaps just
          > > forwarding some common operations (like serialization).[/color]
          >
          > Thanks for taking the time...
          >
          > The problem I have is that Widget itself contains a member
          > of type SubWidget which also needs to have a LightSubWidget
          > counterpart. So the question is how to create the
          > Widget/SubWidget object from the LightWidget/LightSubWidget
          > object - in a way which is reliable and easy to maintain.[/color]

          You lost me. I don't see problem with reliability or easy of
          maintenance if classes have a light core version and a heavier
          decorator that adds functionality (and perhaps data), as long as one
          can be converted to the other. In my mind the portable core code can
          go in the core class and the uglier code that you don't want to port
          can inhabit the heavyweight decorator class. If you do this for all
          Widgets and SubWidgets, conversion should be straight forward.

          But I don't have the whole picture, so I'm willing to take your word
          that this approach won't work for you.
          [color=blue]
          > So far the only simple way I can think of achieving this
          > is to bracket all the heavy code within #ifdefs and set a
          > compiler directive appropriately. It would be nice if there
          > were some better mechanism for maintaining two related sets
          > of objects (in separate source files). But is there?
          >
          > Thanks Jack[/color]

          My approach requires some refactoring, which may require more effort
          than you are able or willing to invest. But if you are using #ifdefs
          to build two separate classes from the same source code, then I
          suspect a redesign may be what is needed.



          Comment

          • Jack

            #6
            Re: Creating and Maintaing Heavy and Light Versions of Classes


            "Derek" <none@none.co m> wrote in message
            news:bti4mr$7jv kh$1@ID-46268.news.uni-berlin.de...[color=blue]
            >
            > You lost me. I don't see problem with reliability or easy of
            > maintenance if classes have a light core version and a heavier
            > decorator that adds functionality (and perhaps data), as long as one
            > can be converted to the other. In my mind the portable core code can
            > go in the core class and the uglier code that you don't want to port
            > can inhabit the heavyweight decorator class. If you do this for all
            > Widgets and SubWidgets, conversion should be straight forward.
            >
            > But I don't have the whole picture, so I'm willing to take your word
            > that this approach won't work for you.
            >[/color]

            First off, thanks for your time.

            Let me try to illustrate with some pseudo code...

            First we have the core classes (I'm omitting LightSubWidget)

            class LightWidget
            {
            public:
            LightWidget();
            LightWidget(con st LightWidget& src);
            LightWidget& operator=(const LightWidget& src);
            void Serialize( CArchive& ar );
            protected:
            double m_data;
            LightSubWidget m_sub;
            };

            These classes now have all the functionality needed by the render app.

            And now I want to derive the main classes which need more functionality

            class SubWidget : public LightSubWidget
            {







            [color=blue][color=green]
            > > So far the only simple way I can think of achieving this
            > > is to bracket all the heavy code within #ifdefs and set a
            > > compiler directive appropriately. It would be nice if there
            > > were some better mechanism for maintaining two related sets
            > > of objects (in separate source files). But is there?
            > >
            > > Thanks Jack[/color][/color]

            // Lots of complicated stuff..
            void calculate();
            void doSomethingTric ky();
            }

            So far so good, but now what about Widget itself?

            I can't just have

            class Widget : public LightWidget
            {
            // Lots of complicated stuff..

            void useSubWidgets()
            {
            m_sub.calculate ();
            }

            void useMoreSubWidge ts()
            {
            m_sub.doSomethi ngTricky();
            }
            };

            because in this case the new members are expecting m_sub to be of type
            SubWidget and not LightSubWidget. I'd need to be forever casting m_sub from
            LightSubWidget to SubWidget.

            What I'd really like is a way of doing this implicitly.

            [color=blue]
            >
            > My approach requires some refactoring, which may require more effort
            > than you are able or willing to invest. But if you are using #ifdefs
            > to build two separate classes from the same source code, then I
            > suspect a redesign may be what is needed.
            >[/color]

            I agree that #ifdefs doesn't feel right but it does at least get around the
            problem of having to port a whole load of code that isn't actually used.

            Thanks
            Jack


            Comment

            • Jack

              #7
              Re: Creating and Maintaing Heavy and Light Versions of Classes

              [ Sorry, the previous post was a little screwed up - I've fixed it up below]


              "Jack" <Jack@nowhere.i n.particular> wrote in message
              news:btjah1$m2n $1@hercules.bti nternet.com...[color=blue]
              >
              > "Derek" <none@none.co m> wrote in message
              > news:bti4mr$7jv kh$1@ID-46268.news.uni-berlin.de...[color=green]
              > >
              > > You lost me. I don't see problem with reliability or easy of
              > > maintenance if classes have a light core version and a heavier
              > > decorator that adds functionality (and perhaps data), as long as one
              > > can be converted to the other. In my mind the portable core code can
              > > go in the core class and the uglier code that you don't want to port
              > > can inhabit the heavyweight decorator class. If you do this for all
              > > Widgets and SubWidgets, conversion should be straight forward.
              > >
              > > But I don't have the whole picture, so I'm willing to take your word
              > > that this approach won't work for you.
              > >[/color]
              >
              > First off, thanks for your time.
              >
              > Let me try to illustrate with some pseudo code...
              >
              > First we have the core classes (I'm omitting LightSubWidget)
              >
              > class LightWidget
              > {
              > public:
              > LightWidget();
              > LightWidget(con st LightWidget& src);
              > LightWidget& operator=(const LightWidget& src);
              > void Serialize( CArchive& ar );
              > protected:
              > double m_data;
              > LightSubWidget m_sub;
              > };
              >
              > These classes now have all the functionality needed by the render app.
              >
              > And now I want to derive the main classes which need more functionality
              >
              > class SubWidget : public LightSubWidget
              > {
              > // Lots of complicated stuff..
              > void calculate();
              > void doSomethingTric ky();
              > }
              >
              > So far so good, but now what about Widget itself?
              >
              > I can't just have
              >
              > class Widget : public LightWidget
              > {
              > // Lots of complicated stuff..
              >
              > void useSubWidgets()
              > {
              > m_sub.calculate ();
              > }
              >
              > void useMoreSubWidge ts()
              > {
              > m_sub.doSomethi ngTricky();
              > }
              > };
              >
              > because in this case the new members are expecting m_sub to be of type
              > SubWidget and not LightSubWidget. I'd need to be forever casting m_sub[/color]
              from[color=blue]
              > LightSubWidget to SubWidget.
              >
              > What I'd really like is a way of doing this implicitly.
              >
              >[color=green]
              > >
              > > My approach requires some refactoring, which may require more effort
              > > than you are able or willing to invest. But if you are using #ifdefs
              > > to build two separate classes from the same source code, then I
              > > suspect a redesign may be what is needed.
              > >[/color]
              >
              > I agree that #ifdefs doesn't feel right but it does at least get around[/color]
              the[color=blue]
              > problem of having to port a whole load of code that isn't actually used.
              >
              > Thanks
              > Jack
              >
              >[/color]


              Comment

              • Jack

                #8
                Re: Creating and Maintaing Heavy and Light Versions of Classes

                Thinking a bit more about my problem, it seems to me that what I really need
                is a mechanism for declaring data members as virtual in the same way as
                member functions can be virtual.

                So ideally it would be great if I could have

                class LightWidget
                {
                public:
                /* core stuff */

                virtual LightSubWidget m_sub;
                };


                and then define

                class Widget : public LightWidget
                {
                public:
                /* tricky stuff */

                virtual SubWidget m_sub;
                };

                But unfortunately that's not allowed

                The best I can come up with is

                class Widget :public LightWidget
                {
                public:
                Widget() : m_subW ((SubWidget&)m_ sub)) {};

                /*tricky stuff

                SubWidget& m_subW;
                };

                But would that have any unforeseen side-effects?

                Thanks
                Jack


                Comment

                • Martijn Lievaart

                  #9
                  Re: Creating and Maintaing Heavy and Light Versions of Classes

                  On Wed, 07 Jan 2004 19:05:28 +0000, Jack wrote:
                  [color=blue]
                  > Hello
                  >
                  > I have a library of calculationally intensive classes that is used both by a
                  > GUI based authoring application and by a simpler non-interactive rendering
                  > application. Both of these applications need to serialise the classes
                  > to/from the same files but only the GUI app needs the full range of class
                  > methods.
                  >
                  > Now, the rendering app needs to be ported to multiple OS's but the GUI
                  > doesn't. In order to reduce the time/cost of porting I'd like to create two
                  > versions of the classes - one that only contains the data plus minimum
                  > methods (mostly copy-construct plus serialisation and a few others) and one
                  > with the full range of methods.
                  >
                  > My initial thought was to define the simple classes as bases classes and
                  > then derive the full classes from these. However, some of the base classes
                  > would contain members which are themselves classes which need to be
                  > simplified and if I converted these to the simpler classes then it's not
                  > clear how I could recover the full functionality in the derived versions of
                  > these. Hope that makes sense ;-)
                  >
                  > Does anyone have any suggestions about how to handle this problem - would
                  > templates be a way around, or maybe smart pointers?[/color]

                  I think what you need is the visitor design pattern. This allows you to
                  define extra operations (but not data!) on the classes in a simple way.
                  You would keep your classes simple, all the GUI stuff goes into visitors
                  and have to be included only in the GUI app.

                  This has the added benefit of decoupling your classes from the GUI used, a
                  worthwile aproach anyhow. It'll make porting the GUI easier as well.

                  If your full classes contain extra data, some simple macro's migth help.

                  #if defined(__Windo ws)
                  class GUIWidgetInfo { ... };
                  #elif defined(__SomeO therWindowingSy stem)
                  class GUIWidgetInfo { ... };
                  #elif defined(NOGUI)
                  class GUIWidgetInfo {};
                  #else
                  #error "No GUI defined"
                  #endif

                  class Widget {
                  GUIWidgetInfo gwi_;
                  ...
                  };

                  But this is not very elegant. If nothing else, it couples GUI to non-GUI
                  data. If you need extra state to be kept you might create wrapper objects
                  that contain these basic objects and use a visitor to add functionality to
                  these basic objects.

                  HTH,
                  M4

                  Comment

                  • tom_usenet

                    #10
                    Re: Creating and Maintaing Heavy and Light Versions of Classes

                    On Thu, 8 Jan 2004 10:13:53 +0000 (UTC), "Jack"
                    <Jack@nowhere.i n.particular> wrote:
                    [color=blue]
                    >
                    >"Derek" <none@none.co m> wrote in message
                    >news:bti4mr$7j vkh$1@ID-46268.news.uni-berlin.de...[color=green]
                    >>
                    >> You lost me. I don't see problem with reliability or easy of
                    >> maintenance if classes have a light core version and a heavier
                    >> decorator that adds functionality (and perhaps data), as long as one
                    >> can be converted to the other. In my mind the portable core code can
                    >> go in the core class and the uglier code that you don't want to port
                    >> can inhabit the heavyweight decorator class. If you do this for all
                    >> Widgets and SubWidgets, conversion should be straight forward.
                    >>
                    >> But I don't have the whole picture, so I'm willing to take your word
                    >> that this approach won't work for you.
                    >>[/color]
                    >
                    >First off, thanks for your time.
                    >
                    >Let me try to illustrate with some pseudo code...[/color]

                    Your problem seems to stem from closely coupling gui and non-gui code.
                    [color=blue]
                    >
                    >First we have the core classes (I'm omitting LightSubWidget)
                    >
                    >class LightWidget
                    >{
                    >public:
                    > LightWidget();
                    > LightWidget(con st LightWidget& src);
                    > LightWidget& operator=(const LightWidget& src);
                    > void Serialize( CArchive& ar );
                    >protected:
                    > double m_data;
                    > LightSubWidget m_sub;
                    >};[/color]

                    The above is all non-gui, so it isn't a "Widget". GUI and non-gui code
                    should be separated into separate classes and heirarchies. This is a
                    fundamental tenet of good OO GUI app design (model, view, controller,
                    etc.) The GUI code depends on the non-GUI code, but not vice-versa.
                    Instead, how about:

                    class Data //or Model?
                    {
                    public:
                    Data();
                    Data(const Data& src);
                    Data& operator=(const Data& src);
                    void Serialize( CArchive& ar );
                    protected:
                    double m_data;
                    SubData m_sub;
                    };

                    (obviously a better name is required)
                    [color=blue]
                    >
                    >These classes now have all the functionality needed by the render app.
                    >
                    >And now I want to derive the main classes which need more functionality
                    >
                    >class SubWidget : public LightSubWidget
                    >{[/color]

                    Instead, how about:

                    class SubData
                    {
                    //...
                    };

                    class SubWidget
                    {
                    SubData* data; //can point to Data::m_sub if necessary
                    //...
                    };

                    class Widget
                    {
                    SubWidget* subwidget;
                    Data* data;
                    //...
                    };

                    Remember that inheritence should be a quite rarely used OO tool -
                    usually containment is far more appropriate. Reserve inheritence for
                    when you have polymorphic behaviour you want to change, by implenting
                    an abstract base class. Don't be afraid of writing forwarding
                    functions to contained objects where appropriate, since you end up
                    with much more flexible heirarchies that if you use inheritence.

                    Tom

                    C++ FAQ: http://www.parashift.com/c++-faq-lite/
                    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

                    Comment

                    Working...