Conceptual OOP Question - AArgh!

BlitzMax Forums/BlitzMax Beginners Area/Conceptual OOP Question - AArgh!

Ant(Posted 2005) [#1]
Hi guys, wondering if you could give me some advice concerning the way to use OOP.

For the purpose of an example, imagine that I am writing some code the that is concerned with moving and manipulating trains. Each train can hold a different number of carriages. I want the code I write to control several trains each with a different number of carriages.

Now from what I have read I would declare a carriage type and store the relevent data for that carriage within that type. That type would also have methods and functions to create carriages, move carriages, draw carriages etc.

Now here is the point I want clarification on. From what I have read I would then create a type train which would store a list of carriages that belong to that train. So every time I create a train it automatically creates carriages.

Am I right so far?

The problem I am having is that when it comes to dealing with the list of carraiges within the type Train, I always end up moving the methods that were originally in the carriage type (move, create, draw etc) into the train type as it seems difficult to access them otherwise.

So my question is this: Am I overcomplicating things and using OOP incorrectly or is it that I just need to understand how to structure the code so type train can access the methods with type carriage.

I really would apprecaite any help on this.
Thanks


Brucey(Posted 2005) [#2]
Your carriages / train types idea sounds fine.
But as far as moving that code from carriage to train, you shouldn't have to. This is one of the nice things about OO.

Here is a small example of how you might go about drawing carriages via the train type:
Type Carriage
	Field somestuff:Int

	Method draw()
		' draw carriage stuff
	End Method
End Type

Type Train
	Field carriages:Carriage[5]

	Method draw()
		' draw train
		
		' draw carriages
		For Local i:Int = 0 To Len(carriages)-1
			carriages[i].draw()
		Next
	End Method
End Type

As an example, it's probably not the best way to store the carriages in the train (and things are not initialized etc, etc), but as I'm only pointing out how might use the carriage types in an OO way, we can ignore that :-p
You might also pass in parameters to your carriage drawing method, so it knows *where* to draw it, etc...

As you have a list of carriages in your train type, anywhere in the train code, by picking a specific carriage, you can call any of the carriage methods to have that carriage do something.
The train itself doesn't need (nor probably wants to know) how to draw a carriage, or do carriage-specific things. That is what the carriage type is there for.

Anyhoo, I hope this helps a little.


Ant(Posted 2005) [#3]
ok, but say I wanted to add another carriage to my train. I assume I'd have the create carriage function within the carriage type - so would I create an addcarriagetotrain method in the train type that called the addcarriage function in the carriage type (I guess you have used the same principal to draw the train - by drawing each individual carriage using the carriages draw method)

Appreciate the help.


gman(Posted 2005) [#4]
IMO adding and removing carriages to a train should fall under the trains domain. thus, type Train should have the methods AddCarriage() and RemoveCarriage(). how you create the carriages i think would be more preference, but should probably fall under the Carriage type.


Ant(Posted 2005) [#5]
So I guess a lot of this is really how you view it and waht makes sense to you - there is no right or wrong answer?


bradford6(Posted 2005) [#6]
something like this may work




Dreamora(Posted 2005) [#7]
Ant: There is a wrong and right answer. OO has the target to encapsulate the stuff that is meant to be together.
This means that everything that modifies and affects this type should be created with functions in this type and not through something from outside. This would break the use of objects (ie outside must not know anything of the way the other object works. It just knows the functions/methods it makes public to operate with it - a realworld example is: do you know how a TV really works when you use it? Normally not. You have the buttons etc to operate with it ... which are the same as functions/methods to objects :-))

The AddCarriageToTrain in the Carriage type for example would be wrong because the Train is the object which is modified thus the AddCarriage method should be here as well.
Sure the other way round it would work as well but its just no "correct" usage of OO design ideas.


Ant(Posted 2005) [#8]
OK, I guess this is the heart of my confusion. So you are saying that anything that alters the type should be contained within that type - so AddCarriage would be in the Train type as its affecting the train object.

So what about drawing the carriages that belong to the train - this is concerned with the train so i assume the method should should be in the train type and work without any reference to any methods within the carriage type?

Thank you all for the comments, very very helpful.


taxlerendiosk(Posted 2005) [#9]
So what about drawing the carriages that belong to the train - this is concerned with the train so i assume the method should should be in the train type and work without any reference to any methods within the carriage type?

No. Have the train's draw method call each of its carriages' draw methods.


Ant(Posted 2005) [#10]
OK- so its ok to have this method outside the train type as its reusing code and its not directly modifying the train type?

Thanks


bradford6(Posted 2005) [#11]
Ant,
Take a look at my code sippet above. I added the display method to the TCarriage type and it is called from within the Ttrain's Display method.

I could turn this into a graphical tool if it would help. let me know.


mudcat(Posted 2005) [#12]
Ant,
I know what you're going through.After making my first test game,it felt so clunky(codewise),that I started reading about OOP in general,instead of coding right now.
I have a question for the rest of you guys,If I createa menu,and that menu has these things-A bckground,buttons with the names One Player,Two Players,High Scores,and Exit,A pointer gfx.When the pointer is over the buttons they change color and double in size.

Here's the OOP question,Do I create a type for each button because they are different and act different when clicked on?Would each of these items above have their own type?
What if I wanted to add more buttons?Do I make more types?
Sorry if this is a simple question.

[added later]
the reason for this question is I was reading some JAVA articles about OOP and this seems to be the way they describe it,using the work class instead of type.
mudcat


taxlerendiosk(Posted 2005) [#13]
OK- so its ok to have this method outside the train type as its reusing code and its not directly modifying the train type?

Well... ok, try thinking of the train as a "container" and the carriages as objects inside it (rather than components of the train). So you are not drawing parts of the train when you draw the carriages, but in fact drawing the things "inside" it.

This will either help, or utterly confuse you...


Diablo(Posted 2005) [#14]
mudcat,
dont do that do somthing like this:

this way you can do different things for different buttons but keep it common. If you want to chang even more you can just extend TButton and change whatever method.


Dreamora(Posted 2005) [#15]
I would go even a step further than you diablo and use function pointers:


Type tbutton

	Field x, y
	Field w, h
    Field handle(button:Int)
	
	Function create:tbutton(x, y, w, h)
	
		Local button:tbutton = New tbutton
		
		button.x = x
		button.y = y
		button.w = w
		button.h = h
		
		Return button
		
	End Function
	
	Method render()
	
		' [ render code ]
		DrawRect x, y, w, h
		
	End Method
	
	Method IsOver(_x, _y)
	
		Return RectsCollide(x, y, w, h, _x, _y, 1, 1)
		
	End Method
	
End Type

Function RectsCollide:Byte(x1:Float, y1:Float, w1:Float, h1:Float, x2:Float, y2:Float, w2:Float, h2:Float)
	If x2 => x1 And x2 + w2 =< x1 + w1 Then
		If y2 => y1 And y2 + h2 =< y1 + h1 Then
			Return True
		EndIf
	EndIf
	Return False
End Function

Global myButton:TButton = TButton.Create(10, 10, 100, 100)
myButton.handle = handle1

Graphics 800, 600, 0, 60

While Not KeyHit(KEY_ESCAPE)

	Cls
	myButton.Render()
	If myButton.handle(MOUSE_LEFT) Then End
	Flip
	
Wend


Function handle1:Int(button:Int)
   	Print "Button number: " + button
   	If IsOver(MouseX(), MouseY()) Then
		Return MouseDown(_button)
   	EndIf
End Function


This way you can have 1 type but millions of different actions that happen when the button is pressed.
The only thing that must be the same is the function header (ie the arguments you give to it, the types of the arguments you give and the type of the return value).


Ant(Posted 2005) [#16]
Thanks Bill, I get what you are doing with the train using the display methods of the carriages. This makes sense to me! Guys, when you plan your code, what guidelines do you have in terms of deciding what goes where? Aside from the one that Dreamora mentioned "...everything that modifies and affects this type should be created with functions in this type and not through something from outside" is there any other rules that you guys stick to and a newbie could use as a form of checklist?

Thanks again folks!


Dreamora(Posted 2005) [#17]
I normally try to find the information that is shared by most objects. This is used to create a "base type".
(for example vehicle if you have bike, car, bus, ...)

The other types then extend this with their own "unique" properties.
This way you can for example create a list of vehicles and use the vehicles common abilities and if needed cast to an extended type which is very usefull