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

D

dotnetbuddha

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();
}
...
...
}
 
V

Victor Bazarov

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:

??? 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
 
C

Christopher Pisz

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.
 
S

Stefan Ram

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/
 
D

dotnetbuddha

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 ?
 
V

Victor Bazarov

[..]
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
 
G

Gerhard Fiedler

Victor said:
[..] 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
 
J

Jorgen Grahn

....

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,744
Latest member
CortneyMcK

Latest Threads

Top