Jump to content
  • Advertisement
Sign in to follow this  
Imprecision

OOP design question

This topic is 2172 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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. Edited by Imprecision

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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. Edited by Mussi

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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). Edited by SimonForsman

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!