Best way to access information inside classes?
Monkey Forums/Monkey Programming/Best way to access information inside classes?
| ||
The code I have below uses three different processes to accomplish the same thing. The first passes the entire objects into a Function, the second passes the object fields separately, the third uses a method inside the class and passes the fields in individually. I can also envision a process where I create properties/getters and setters to access the information. My question is, which is the better way to do it? I would imagine that as a function, passing in the fields individually makes the function more generic, because it isn't dependent on my custom GameObject type, but I'm unsure what other considerations are important. My concerns are: 1) If I want to not only access the information, but also potentially modify the values of any given field inside an object, using a function or method, which is the best approach? 2) Which is easier on memory, passing the whole object in each frame or passing in parameters separately, or accessing each field as a property? 3) If I create an arraylist of objects, how does that change the approach, pass each object, pass each field, or get/set each field from within the function or method? 3) What am I missing in terms of considerations? Strict Import mojo Class MyGame Extends App Field gameObject1:GameObject Field gameObject2:GameObject Field flag:Int Field flag2:Int Field flag3:Int Field direction1:Float=1 Field direction2:Float=1 'This contains our application as a whole, including game and title screens and any others we create. Method OnCreate:Int() SetUpdateRate(60) gameObject1 = New GameObject(10, 10, 20, 20) gameObject2 = New GameObject(35, 30, 20, 20) Return 0 End Method OnUpdate:Int() gameObject1.xPos = gameObject1.xPos + 2*direction1 gameObject2.xPos = gameObject2.xPos + 1*direction2 flag = CheckCollision(gameObject1, gameObject2) flag2 = CheckCollision2(gameObject1.xPos, gameObject1.yPos, gameObject1.width, gameObject1.height, gameObject2.xPos, gameObject2.yPos, gameObject2.width, gameObject2.height) flag3 = gameObject1.CheckCollision3(gameObject2.xPos, gameObject2.yPos, gameObject2.width, gameObject2.height) If gameObject1.xPos + gameObject1.width >= DeviceWidth() direction1 = -1 End If gameObject1.xPos <= 0 direction1 = 1 End If gameObject2.xPos + gameObject2.width >= DeviceWidth() direction2 = -1 End If gameObject2.xPos <= 0 direction2 = 1 End Return 0 End Method OnRender:Int() Cls(0,0,0) gameObject1.Draw gameObject2.Draw DrawText(flag, DeviceWidth()/2, DeviceHeight()/2) DrawText(flag2, DeviceWidth()/2, DeviceHeight()/2 + 12) DrawText(flag3, DeviceWidth()/2, DeviceHeight()/2 + 24) Return 0 End End Class GameObject Field xPos:Float Field yPos:Float Field width:Float Field height:Float Method New(x:Float, y:Float, w:Float, h:Float) Self.xPos = x Self.yPos = y Self.width = w Self.height = h End Method Draw:Void() SetColor(0, 255, 0) DrawRect(Self.xPos, Self.yPos, Self.width, Self.height) End Method CheckCollision3:Int(x2:Float, y2:Float, w2:Float, h2:Float) If Self.xPos > (x2 + w2) Or (Self.xPos + Self.width) < x2 Return 0 End If Self.yPos > (y2 + h2) Or (Self.yPos + Self.height) < y2 Return 0 End Return 1 End End Function CheckCollision:Int(object1:GameObject, object2:GameObject) If object1.xPos > (object2.xPos + object2.width) Or (object1.xPos + object1.width) < object2.xPos Return 0 End If object1.yPos > (object2.yPos + object2.height) Or (object1.yPos + object1.height) < object2.yPos Return 0 End Return 1 End Function CheckCollision2:Int(x1:Float, y1:Float, w1:Float, h1:Float, x2:Float, y2:Float, w2:Float, h2:Float) If x1 > (x2 + w2) Or (x1 + w1) < x2 Return 0 End If y1 > (y2 + h2) Or (y1 + h1) < y2 Return 0 End Return 1 End Function Main:Int() New MyGame Return 0 End |
| ||
So no one has any input on this? Maybe if I frame the question differently. Why choose a function vs. a method? After that choice, why choose to pass individual parameters vs. passing whole objects vs. accessing information with properties or getters/setters? |
| ||
To some extent, if you don't know the answer, the question doesn't matter here. Because in every case you are doing the same thing. The only issue is what will give you code that looks nice, has fewer bugs, is easier to extend etc. For example, you *can* use object methods and properties to hide the internal implementation of xPos and yPos. But whether that really gains you anything depends on how likely the implementation is to change. I prefer the first version of CheckCollision because it is easier to read, and it does not affect the objects that are passed as parameters. You could make similar functions called Move( object:Object ) and Bounce( object:Object ) to cover what you do in OnUpdate() - but in this case you must note that Bounce() affects the object parameters. I would usually prefer to call such functions rather than dump everything in Update() [my bananas example notwithstanding]. The thing with object orientation is that trying to find the perfect system is a waste of time. Find a reasonably decent and fairly consistent way of doing things. With more experience it will come easier as you will be coding with a better eye as to what you will be doing later. |
| ||
"My question is, which is the better way to do it?" -it depends and also doesn't matter that much for now. "Why choose a function vs. a method?" functions are static while methods need an instance. I would imagine functions are faster because of that. but generally instance methods are more OOP and look cleaner (to me atleast) " pass individual parameters vs. passing whole objects vs. accessing information with properties" again this depends on personal taste etc. but I like my api to be clean and small, so if your code would test if two gameobjects overlap it makes sense to pass in two gameobjects. (opposed to 8 parameters) or pass in one gameobject to an instance method. like Method IsCollidingWith(other:GameObject) on the other hand your code seems to test if two rectangles overlap so a static function (in some utility class) like Function RectsOverlap(rect1:Rectangle, rect2:Rectangle) would seem logical too. |
| ||
Thanks a lot for the replies. I understand that the answer varies, most answers do, but I was just sort of looking for some rules or thumb that may or may not contradict my own. Here's how I typically rationalize these choices: When I use methods: If what I need to do only uses or modifies the information for the object itself, I typically make a method to do it, so the functionality is with the data. I use this rule even if there is some necessary external "trigger" that needs to go off to make this happen. When I use functions: If the process needs to do one particular thing, but needs to do that thing to many of the same or different objects, I typically use a function. Whether I pass parameters, or objects, or use properties: If what I need to do is generic enough, and there are a limited number of properties, I use individual properties that are type int, float, etc. I do this so I can reuse the function as much as possible with different things. If the function/method needs to take in lots of data, and that data is specific to the type of object(s), then I pass objects in. I don't typically find use for properties, or getters and setters, but maybe that is because I work alone? While I can see how they work, I'm curious what the primary reason for using those are. The main issue is that while I've written lots of code over the years, I'm an engineer, not a computer scientists/programmer by training. So I'm pretty good at solving problems, and can get almost anything to work, and even work well, but I have no idea what the "best approach" is. Therefore, even though I'm successful, I'm curious whether or not my practices are sound, in general. Any other feedback people can provide would be appreciated. |
| ||
Just watched this video yesterday, and there are a few thoughts on this half an hour in : 30:09 https://www.youtube.com/watch?feature=player_embedded&v=c-kav7Tf834 |