Question on Best Practice regarding set and get method in class composition...

Hi, I’ve got a philosophical question about the set and get methods of classes. I will try to make it clear…

Let say we have typical user class called « classC » with set and get methods, like:

1
2
3
4
5
6
7
8
9
Class C
{
…
int value
…
void setValue (const int intValue);
int getValue();
…
}


Then we’ve got a classB that have a vector of classC (composition, not inheritance) :

1
2
3
4
5
6
7
8
Class B
{
	…
	vector<classC> vectorC;
	…
	const vector<classC> & getVectorC() const;
	…
}


And a class classA wich one composed of classB :

1
2
3
4
5
6
7
8
Class A
{
	…
	vector<classB> vectorB;
	…
	const vector<classB> & getVectorB() const;
	…
}


This could go on and on…

I put the return value of the get methods as a reference cause I don’t want to have a copy of the vector for memory and performance consideration. I set the returned reference constant to ensure no direct modification of value in vectors…

What is the best practice to modify the value variable of a classC object contains in the vectors of classA? I see two ways, but cannot define which on is the best :

1. Create a temporary classC object, assign it a copy of the classC object to modify, modify the value with the set method, delete the original class object in the vector and push the new one. Which is a couple of operation, like :

1
2
3
4
5
6
7
8
9
10
classC tempC;
std ::vector<classC> ::iterator fwdIterator;
// use a loop or other mean to set the iterator to the correct classC object// the classes contain the assignment operator overload…
tempC = *fwdIterator; 
tempC.setValue(z);
	
classAObj.getVectorB().at(x).getVectorC().erase(fwdIterator);
classAObj.getVectorB().at(x).getVectorC().push_back(tempC);


2. Create a setValue method in classA and classB to allow direct modification of classC value :

in classB :

1
2
3
4
void setClassCValue(const int position, const int newValue)
{
	vectorC.at(position).setValue(newValue);
}


and then in classA :

1
2
3
4
void setClassCValue(const int bPos, const int cPos, const int newValue)
{
	vectorB.at(bPos).setClassCValue(cPos, newValue);
}


If there is a lot of data manipulation, the second choice seems more interesting because a simple call to classA set method is required. But as there are more and more variables in class B and C, and more composition, the number of set methods to define will increase rapidly…

So, what would be the « best pratice » ?

Regards,

Éric
Last edited on
I personally like your option 2; however, where possible, I would make these classes templates.

Great question!
I much prefer the second method.

The first method breaks "encapsulation". Encapsulation is when you hide the implementation details from the programmer. This means that you can modify the implementation without breaking the code of the programmer who is using your class.

In your first method you provide the std::vector to the programmer through a function call. This means that the programmer may write a lot of code specifically expecting a std::vector. Internally you may decide that std::vector needs to be replaced by std::set. Unfortunately that would break some of the programmer's code. In order to keep the programmer's code working you would still have to return a std::vector because his code is expecting that. So remaining compatible with the programmer's code could get unwieldy and expensive.

Encapsulation is designed to minimise this problem. By providing a good interface to manipulate your object (rather than handing out the internal details) the programmer can code to that interface without fear that the internal implementation could change.

Galik, very well said, sir!
Thanks Galik, you convinced me...

Kooth, I don't see how class templates will make it easier in my example. Can you elaborate please?

Éric
What I had in mind about templates was something like this:

1
2
3
4
5
6
7
8

template< class T >

void setClassCValue(const int position, const T newValue)
{
	vectorC.at(position).setValue(newValue);
}


This would take care of different types of native types if your class had them.


That sounds good. I just have to overload the setValue method.

But what if classC has variables that have the same data type? There is somewhere in my mind a thought about passing a function, or a pointer to a function, to a function but it is very foggy…
Well, you wouldn't need a template solution.
What is the best practice to modify the value variable of a classC object contains in the vectors of classA?
Nope, classA contains a vector of classB. It should not be aware of the existence of classC. (considering that B is not a mere wrapper container)

Your first method will not compile, as you return a const reference from getVectorC. However if you already have the iterator, ¿why don't just fwdIterator->setValue(z); ?

But as there are more and more variables in class B and C, and more composition, the number of set methods to define will increase rapidly…
Don't think of your classes are mere data containers. In that case it will better to make the members public.*
Also the chain will not be always direct, you may want to perform several actions together, or the message could be changing.

You may want to read about Law of Demeter and Tell, don't ask


*why getters and setters are evil http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html?page=1
Topic archived. No new replies allowed.