Best way to access methods of Objects and its sub-Objects

Discussion in 'C++' started by dotnetbuddha@googlemail.com, Apr 26, 2013.

  1. Guest

    Hi All,
    I was always unsure as how to deal with cases where one has to access methods of objects contained with in the class. Basically, if we have a complex system as a car, where things can be abstracted in several classes, what isthe ideal way to access one/several methods of an object contained in the class, which inturn contain additional classes ?

    To explain what I mean, i wrote some pseudo code below. For example, I liketo check the health of the car. While coding, I would normally prefer method-1 where the task of checking is delegated to each individual method. Where as some of my collegues argue this leads to several methods which do nothing but delegating the task further down. And suggest something like in method-2.

    I am grateful for your time and suggestions. Thank you.



    Pseudo code:
    -----------

    class Tyre;
    class MovingParts
    {
    ...
    ...
    Tyre m_Tyre;
    public:
    Tyre* GetTyre() { return &m_Tyre; }
    void CheckTyrePressure()
    {
    m_Tyre.CheckTyrePressure();
    }
    };

    class Car
    {
    ...
    ...
    MovingParts m_movingParts;
    public:
    ...
    ...
    bool CheckCarHealth()
    {
    ...
    m_movingParts.CheckTyrePressure();
    ...
    }

    MovingParts* GetMovingPartsHandler()
    {
    return &m_MovingParts;
    }
    };



    int main()
    {
    std::list<Car*> myCars;
    ...
    ...
    // Check the health of all cars
    for (std::list<Car*>::iterator carIdx=myCars.begin(); carIdx!=myCars.end(); ++carIdx)
    {
    // Method-1
    carIdx->CheckCarHealth();
    // Method-2
    carIdx->GetMovingPartsHandler()->GetTyre()->CheckTyreProfile();
    }
    ...
    ...
    }
     
    , Apr 26, 2013
    #1
    1. Advertising

  2. On 4/26/2013 11:47 AM, wrote:
    > Hi All,
    > I was always unsure as how to deal with cases where one has to
    > access

    methods of objects contained with in the class. Basically, if we have a
    complex system as a car, where things can be abstracted in several
    classes, what is the ideal way to access one/several methods of an
    object contained in the class, which inturn contain additional classes ?
    >
    > To explain what I mean, i wrote some pseudo code below. For example,
    > I

    like to check the health of the car. While coding, I would normally
    prefer method-1 where the task of checking is delegated to each
    individual method. Where as some of my collegues argue this leads to
    several methods which do nothing but delegating the task further down.
    And suggest something like in method-2.
    >
    > I am grateful for your time and suggestions. Thank you.
    >
    >
    >
    > Pseudo code:
    > -----------
    >
    > class Tyre;


    ??? No known interface in Tyre...

    > class MovingParts
    > {
    > ...
    > ...
    > Tyre m_Tyre;
    > public:
    > Tyre* GetTyre() { return &m_Tyre; }
    > void CheckTyrePressure()


    Probably

    void CheckTyrePressure() const

    (or does checking pressure changes the state of 'MovingParts' object?)
    and perhaps there is some kind of side effect since this function does
    not seem to return any value, nor does it have any arguments beyond
    'this'. Consider documenting that somehow.

    > {
    > m_Tyre.CheckTyrePressure();


    The compiler is unlikely to accept this code without seeing the
    definition of 'Tyre' type.

    > }
    > };
    >
    > class Car
    > {
    > ...
    > ...
    > MovingParts m_movingParts;
    > public:
    > ...
    > ...
    > bool CheckCarHealth()


    bool CheckCar

    > {
    > ...
    > m_movingParts.CheckTyrePressure();
    > ...
    > }
    >
    > MovingParts* GetMovingPartsHandler()
    > {
    > return &m_MovingParts;
    > }
    > };
    >
    >
    >
    > int main()
    > {
    > std::list<Car*> myCars;
    > ...
    > ...
    > // Check the health of all cars
    > for (std::list<Car*>::iterator carIdx=myCars.begin(); carIdx!=myCars.end(); ++carIdx)


    In C++11 consider doing

    for (Car* pCar : myCars)

    > {
    > // Method-1
    > carIdx->CheckCarHealth();
    > // Method-2
    > carIdx->GetMovingPartsHandler()->GetTyre()->CheckTyreProfile();
    > }
    > ...
    > ...
    > }


    If your question is purely about the differences I see between the two
    ways of invoking the interface, then my answer is to hide it. Hidden
    interface is the best abstraction, the ultimate black box. The code
    that uses the results does not have to know even that the interface
    actually exists. The the outside observer the car can check its health
    and what it entails is of no consequence. Unless they actually know
    what they are looking for, in which case you probably want to design a
    special "mechanic" interface who would request all those part-by-part
    interfaces and interrogate those individually...

    To conclude: create those interfaces that your user is going to want to
    use. If you can see both uses, create both interfaces.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Apr 26, 2013
    #2
    1. Advertising

  3. On 4/26/2013 10:47 AM, wrote:
    > Hi All,
    > I was always unsure as how to deal with cases where one has to access methods of objects contained with in the class. Basically, if we have a complex system as a car, where things can be abstracted in several classes, what is the ideal way to access one/several methods of an object contained in the class, which inturn contain additional classes ?
    >
    > To explain what I mean, i wrote some pseudo code below. For example, I like to check the health of the car. While coding, I would normally prefer method-1 where the task of checking is delegated to each individual method. Where as some of my collegues argue this leads to several methods which do nothing but delegating the task further down. And suggest something like in method-2.
    >
    > I am grateful for your time and suggestions. Thank you.
    >
    >
    >
    > Pseudo code:
    > -----------
    >
    > class Tyre;
    > class MovingParts
    > {
    > ...
    > ...
    > Tyre m_Tyre;
    > public:
    > Tyre* GetTyre() { return &m_Tyre; }
    > void CheckTyrePressure()
    > {
    > m_Tyre.CheckTyrePressure();
    > }
    > };
    >
    > class Car
    > {
    > ...
    > ...
    > MovingParts m_movingParts;
    > public:
    > ...
    > ...
    > bool CheckCarHealth()
    > {
    > ...
    > m_movingParts.CheckTyrePressure();
    > ...
    > }
    >
    > MovingParts* GetMovingPartsHandler()
    > {
    > return &m_MovingParts;
    > }
    > };
    >
    >
    >
    > int main()
    > {
    > std::list<Car*> myCars;
    > ...
    > ...
    > // Check the health of all cars
    > for (std::list<Car*>::iterator carIdx=myCars.begin(); carIdx!=myCars.end(); ++carIdx)
    > {
    > // Method-1
    > carIdx->CheckCarHealth();
    > // Method-2
    > carIdx->GetMovingPartsHandler()->GetTyre()->CheckTyreProfile();
    > }
    > ...
    > ...
    > }
    >
    >



    In my opinion this is why you start with requirements before coding.
    Do you have a use case where the user would want to interact with tire
    objects directly? Are they concerned with each individual tire? Perhaps
    they'd like to modify tires? Or is your user only concerned with the car
    as a whole?

    In the former case, I'd provide get and set methods for tires in the car
    interface and allow the user to interact with tires or references to
    tires directly. In the latter case, I'd hide the details of tire
    interactions withing the implementation of the car class.

    If unsure, then go the second route, but make it easy to provide get and
    set methods for tires later and a proper tire interface, such that
    actions can be taken on the tire directly later if needed. There is no
    problem having both IMO. You want to check car health, which in turn
    checks tire pressure? fine. Later on the customer, wants to look at each
    individual tire? Fine, get and set tire added to car, caller gets each
    tire from car and calls check pressure, get serial number, get tread,
    etc. on each tire individually.

    In summary, Opt for the second choice, but let your requirements guide you.
     
    Christopher Pisz, Apr 26, 2013
    #3
  4. Stefan Ram Guest

    writes:
    >I was always unsure as how to deal with cases where one has
    >to access methods of objects contained with in the class.


    Which class is »the class«?

    When objects are »contained« in a class, these are
    static fields. How to access a static field of a
    class should be obvious.

    >Basically, if we have a complex system as a car,


    A car is not a object-oriented program, although
    some books suggest otherwise.

    >where things can be abstracted in several classes,


    What does »to abstract a thing in a class« does
    suggest to you?

    >what is the ideal way to access one/several methods of an
    >object contained in the class, which inturn contain
    >additional classes ?


    A class cannot be contained at run time.
    (A class is not a run-time value.)

    So, I ignore the last clause.

    Then I get:

    >what is the ideal way to access one/several methods of an
    >object contained in the class


    When one knows the answer for »one« one knows
    the answer for »several«, so I get:

    ~what is the ideal way to access a method of an
    ~object contained in a class?

    Methods are /invoked/, fields are accessed, thus:

    ~What is the ideal way to invoke a method of an
    ~object contained in a class?

    Well, if an object o is contained in a class C,
    it has to be in a static field f of C, so a
    method m of o is invoked as

    C::f.m()

    What you actually want to ask might be:

    ~Where can I learn more about the design of C++
    ~classes and OOA/OOD?

    and the answer is:

    By reading (in this order and doing the exercise):
    Programming -- Principles and Practice Using C++ (only if
    you have not programmed before) or Accelerated C++ (if you
    have programmed before), The C++ Programming Language,
    Effective C++, Exceptional C++ (Parts 1 and 2), Modern C++
    programming.

    And also:

    Design Patterns by Gamma, et. al.
    Refactoring by Martin Fowler
    Applying UML and Patterns, 3rd Ed. by Craig Larman

    Structured Systems Analysis (DeMarco)
    Patterns of Enterprise Application Architecture by Fowler
    Object Oriented Software Construction by Bertrand Meyer
    Object Oriented Software Engineering by Ivar Jacobson
    Code Complete, 2nd Ed. by Steve McConnell
    Test-Driven Development by Kent Beck
    The Pragmatic Programmer by Andrew Hunt
    The Mythical Man-Month by Frederick Brooks
    Domain Driven Design by Eric Evans

    Online:

    http://www.objectmentor.com/resources/articles/ocp.pdf
    http://www.cs.cmu.edu/afs/cs/project/vit/ftp/pdf/intro_softarch.pdf
    http://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf
    http://www.laputan.org/mud/
     
    Stefan Ram, Apr 26, 2013
    #4
  5. Stefan Ram Guest

    Stefan Ram, Apr 26, 2013
    #5
  6. Guest

    Thank you all for your thoughtful answers.

    @Stefan: You may find it hard to believe but I am an experienced programmer.. Your comments clearly indicate that I should learn to *speak* in C++ rather than just *think* in it.

    I am also sorry for the errors in the Pseudo code. I did not review it before posting. I rather concentrated on my question part only.

    The Pseudo code I gave as example, comes no where near to the system we have at work. We offer wide range of interfaces, right from something as abstract as checking the Car's health, to something as detailed as the pressure of the tyre, its serial number, etc etc. Therefore, the requirements demands that we offer much detailed access to our system.

    Using the method-2, it becomes much easier to handle every possible case. But it has the disadvantage that, error handling gets very difficult (Ex: What if there are no tyres ?)

    Whereas in Method-1, I like the black box approach, where the User just invokes the interface without actually worrying what lies underneath.

    From what I understand reading your comments, there is no *one* way, but rather both ways can/should be used simultaneously, given the wide range of interfaces we offer to the User ?
     
    , Apr 27, 2013
    #6
  7. On 4/26/2013 8:44 PM, wrote:
    >[..]
    > From what I understand reading your comments, there is no *one* way,
    > but rather both ways can/should be used simultaneously, given the
    > wide range of interfaces we offer to the User ?


    You misunderstand, or so it seems. The way is not dictated by *you*,
    the implementor of the class/interface, but by the user of it. Provide
    the interface that will be used. If both are needed, provide both. If
    you provide both, they *can* be used simultaneously (that's the user's
    prerogative), but AFA design is concerned, the word "should" has no
    place, IMHO.

    Now, how do you figure out which interface is *likely* to be used? You
    need to put yourself in the shoes of the user and imagine the likely
    application of your types. The rest of the story is to be written by
    the market, so to speak. If you have unlimited resources, provide all
    the interfaces you can think of. If your resources are of the real
    world, then you will need to pick the most likely to be used, and
    concentrate on making them convenient and robust.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Apr 27, 2013
    #7
  8. Victor Bazarov wrote:

    > On 4/26/2013 8:44 PM, wrote:
    >> [..] From what I understand reading your comments, there is no *one*
    >> way, but rather both ways can/should be used simultaneously, given
    >> the wide range of interfaces we offer to the User ?

    >
    > You misunderstand, or so it seems. The way is not dictated by *you*,
    > the implementor of the class/interface, but by the user of it.
    > Provide the interface that will be used. If both are needed, provide
    > both. If you provide both, they *can* be used simultaneously (that's
    > the user's prerogative), but AFA design is concerned, the word
    > "should" has no place, IMHO.
    >
    > Now, how do you figure out which interface is *likely* to be used?
    > You need to put yourself in the shoes of the user and imagine the
    > likely application of your types. The rest of the story is to be
    > written by the market, so to speak. If you have unlimited resources,
    > provide all the interfaces you can think of. If your resources are
    > of the real world, then you will need to pick the most likely to be
    > used, and concentrate on making them convenient and robust.


    Something that has been missing so far IMO is encapsulation.

    Let's say you add the possibility to add a turbo charger to the motor
    and now may have to check an optional turbo charger for health. If there
    are a dozen places in the code that use method 2, they all have to be
    kept up to date with this change. If they all use a single "black box"
    interface like method 1, the change is restricted to (encapsulated in) a
    single function.

    So, going back to Victor's point, if there is a requirement to be able
    to "check the (whole) car's health", this is a strong indicator that you
    want a single function that encapsulates this, a la method 1. While
    method 2 in principle provides the means to fulfill the requirement, it
    makes it error-prone and awkward.

    Gerhard
     
    Gerhard Fiedler, Apr 29, 2013
    #8
  9. Jorgen Grahn Guest

    On Fri, 2013-04-26, Christopher Pisz wrote:
    > On 4/26/2013 10:47 AM, wrote:
    >> Hi All,
    >> I was always unsure as how to deal with cases where one has to
    >> access methods of objects contained with in the class.

    ....

    > In my opinion this is why you start with requirements before coding.
    > Do you have a use case where the user would want to interact with tire
    > objects directly? Are they concerned with each individual tire? Perhaps
    > they'd like to modify tires? Or is your user only concerned with the car
    > as a whole?


    I'd put that differently, since IME it's rare to have actual
    requirements on this level.

    If you start doubting what the class interface should look like, try
    leaving it aside for a while and work on the code which /uses/ the
    class. (Assuming you're responsible for that code too; if you aren't,
    then you are a library designer and that's a much harder job.)

    If I focus on just the Car class and its unit tests, I tend to come up
    with a lot of interface which isn't needed or is too elaborate.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, May 16, 2013
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ben
    Replies:
    2
    Views:
    901
  2. Lawrence D'Oliveiro

    Death To Sub-Sub-Sub-Directories!

    Lawrence D'Oliveiro, May 5, 2011, in forum: Java
    Replies:
    92
    Views:
    2,044
    Lawrence D'Oliveiro
    May 20, 2011
  3. thunk
    Replies:
    1
    Views:
    315
    thunk
    Mar 30, 2010
  4. thunk
    Replies:
    0
    Views:
    489
    thunk
    Apr 1, 2010
  5. thunk
    Replies:
    14
    Views:
    628
    thunk
    Apr 3, 2010
Loading...

Share This Page