OOP design question

Started by
14 comments, last by Telastyn 11 years, 9 months ago
Hi there,

I asking myself for a while how to design correctly.
Let me get an example: (C#)
[source lang="csharp"]class SimpleClass
{
private int a = 0;
private int b = 0;
private int c = 0;

public SimpleClass(int a, int b)
{
this.a = a;
this.b = b;

CalcC(); // CALL DESIGN A
this.c = CalcC(this.a, this.b); // CALL DESIGN B
}

//METHOD DESIGN A
private void CalcC()
{
c = a + b;
}

//METHOD DESIGN B
private int CalcC(int first, int second)
{
return first + second;
}
}[/source]

I always used variant A when working with private methods. But then I realised that I can't put my methods in unit tests, because they are working with the class properties and don't return any values.

I working like variant A since years, and it would be nice if somebody can tell me something about this and the dos and don'ts of this.

Thanks.
Advertisement
it depends on your use case. if your function always just works on the a and b member, then it's enough to have only CalcC(), if you can reuse CalcC for other values, then it might be better to have Design B. If you use it on members as well as on 'other' parameters, then implement CalcC with parameters and overload it also with a parameter free version, that calls the version using the members as parameters. (In no case you shall implement it twice ;) ).
I think your unit testing would then still work.
I'm not sure about c#, but in c++ I'd implement the parameter version as static function, so it could be called as an utility from outside. if you have a bunch of those CalcC functions, I'd even consider to create a separate class, holding the static parameter-versions of all those CalcC functions.
I think the answer has something to do with semantics. I for one expect a function with the word calculate in it's name to return something and not hide the result somewhere in the background. Design A is also not very explicit in what it does, the function name informs us it assigns a value to c, but I don't think it's the right place for that. The function name should specify what it calculates(what is c?) and the variable you assign it to then speaks for itself.

I always try to write code that doesn't require documentation to understand what's going on, it's easier to maintain and share that way.
My guidelines is if it's a private method and always works on the same variables, then it's method A. Otherwise, it's method B.

In most cases, I initially used method A, and as the code grows, I would refactor that to method B when the need arises. So don't think that you are stuck with one, you can always refactor them.
The primary difference between the two is that design A is coupled to the class's variables, uses message coupling and is more stateful whereas design B is more functional and reusable. If you desire to clean up the constructor to make it more readable or possibly delay construction of an object until later then design A may be suitable and out in the wild this would be seen as a typical Initialize() method. Design B would be more preferable if you want to lower the amount duplicate code because of its use all around the class or you could even make it protected for child classes to utilize. Like Mussi pointed out methods provide metaphor for the code they contain, it is just as important (if not more so) to give correct and meaningful metaphor to code as anything else. So my answer is it depends on the method's use, which may change over the project's development cycle.

I would also like to point out that design A makes the class more procedurally coupled, since you cannot determine the value of c until you have the values a and b. This is something you want to typically avoid if possible but I understand it is a contrived example.
In general, you should prefer methods that do not cause side effects.

In general, you should prefer methods that do not cause side effects.

do you imply that a function that is supposed to calc something based on members, is having side effects although it's on purpose?
otherwise I'm confused what you could possibly mean, could you make your reply more detailed?
So the first CalcC has a side effect. That is, it modifies the program state by mutating c.

The second CalcC has no side effects. It takes input and returns an output. The second form has a number of advantages in design, testing, and concurrency.

In general, you should prefer methods that do not cause side effects.


i think that a method that has no sideffects and is unaffected by the current state(a pure function) most likely doesn't belong in the class. in my opinion a non static class really should only have methods causing or relying on sideeffects.

i think Method B should be a public static method in a static support class (in C++ it should be a free function imo).
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

[quote name='Telastyn' timestamp='1341972634' post='4957857']
In general, you should prefer methods that do not cause side effects.


i think that a method that has no sideffects and is unaffected by the current state(a pure function) most likely doesn't belong in the class. in my opinion a non static class really should only have methods causing or relying on sideeffects.

i think Method B should be a public static method in a static support class (in C++ it should be a free function imo).
[/quote]

I agree, but that's a different discussion.

This topic is closed to new replies.

Advertisement