Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Don't forget to read Tuesday's email newsletter for your chance to win a free copy of Construct 2!


Am I thinking right OO way?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
67 replies to this topic

#41 Ravyne   GDNet+   -  Reputation: 7778

Like
6Likes
Like

Posted 02 March 2011 - 11:34 AM


"You can't grantstand on "fighting the established order of things" without nodding to the fact that many of the "rigid" standards have already weathered generations of cynicism, scrutiny, and testing through application. You also have to accept that the answer to "questioning those before us" is sometimes "well, yes, they WERE right.""

Very true. They often are. But I just don't live my life blindly. I don't see the point in living life by the book without questioning it. But the matter at hand can't be tested XD That's why I stated that it's not science. There's no measurement for success. There's no performance increment to look at. If you can't test it, isn't it an opinion? If someone tells you that the sky is green what if they really see it as such? There's no way to prove them otherwise but by collective "opinion".


It's one thing to question things, and honestly you are entirely within your right to say "Well, I know I'm violating established practice, but it hasn't blown up in my face yet, so I'm fine with it." however, composition vs. inheritance, and the appropriate use of such, is well established in the computer science community. As I stated earlier, LSP and SRP have been vetted by hundreds of smart people over the past 30-40 years -- you may not see the difference adhering to these principles make in small projects, but in large projects which change and have to be maintained and extended over time, you will rue the day you chose inheritance over composition when it was not warranted.

You charge that the benefit is immeasurable and therefore opinion -- false on both accounts. While hard numbers like performance or binary measurements like "well, did it work in the end" don't seem to indicate a difference, and "source code quality" might seem far too subjective to be a useful measure, I would argue that the latter is not as subjective as it seems, and indeed at least as useful a measure as the former.

Let us assume that there exists a group of very smart computer scientists, and let us assume that they have written a great deal of software, much of it medium or large-scale. Let us also assume that they have an academic and professional interest in developing the best methods possible, and that originating said methods is incentively (prestige, better jobs). Now let us assume that these people, having gotten together to share their experiences noticed certain patterns across their independently-developed projects. They talk about what works and where their individual solutions fall flat, and over time they co-develop a solution to a particular problem that seems to have the greatest benefit and the least amount of headache in aggregate. This is what a Design Pattern is (keeping in mind that a pattern is just an idea to be applied, not a thing to be applied.), this is what idioms are, this is what stands behind "theories" like LSP, SRP and innumerable others.

What you seem to insist on arguing, is that your one opinion, based on your own limited experience, should call into question the collective work of literally thousands of man-years of insight on these topics. If that's what you want to *do* then fine, go do so -- I'm confident enough in these assertions to say that, without question, your casting aside of these principles will one day make your programming life more difficult than it need be. But I would be remiss as a member of this community and as something of a computer scientist myself, if I did not counter such wild claims. You offered a solution that works, I offered one which "is better" -- and I can't point you to a chart or statistics, only to the collective experience of hundreds of minds greater than my own, or your own. If you want to take those odds on, so be it, but to recommend following suit is negligent.

Sponsor:

#42 way2lazy2care   Members   -  Reputation: 782

Like
0Likes
Like

Posted 02 March 2011 - 12:02 PM

I thought I made that fairly clear with the 'no inheritance' bit, but here goes...

Four concrete classes: Paddle, Player, Enemy and World (rename as you see fit). Player and Enemy each hold an instance of Paddle via composition. Paddle contains a position, and a collision primitive. Player processes input and moves the player paddle, Enemy performs AI and moves the enemy paddle. World contains references to both Paddles (*not* Player and Enemy), and simulates the ball.

Even though Player and Enemy may share certain attributes, there is no reason for them to present a uniform interface, because there is no client to make use of that shared interface.

I was under the impression that the Player and Enemy classes would be holding relevant player data, not controlling the paddle. I guess this depends on how complicated the rest of the game gets. I think we just have different concepts of the scope it should be designed for.

Player and Enemy should be the subclass of some class if you want to extend to have more than 2 players so they can be stored in a player array or have variable numbers of ai and human players.

#43 XXChester   Members   -  Reputation: 919

Like
0Likes
Like

Posted 02 March 2011 - 12:04 PM

I wouldn't think about the number of classes versus the size of the game. When I am designing games or applications I think about how to logically break things up into classes that makes sense. In the end, my solution may be 4x larger with all of the class definitions and extra curly braces and other crap but my design is a true object oriented approach and easily maintainable opposed to 1 UBER class that has everything in it.

When I wrote a pong clone I had the following;
-Abstract paddle class
-Enemy class extends paddle
-Player class extends paddle
-Ball class
-Wall class that were the outter boundaries for collision

Remember to mark someones post as helpful if you found it so.

http://www.BrandonMcCulligh.ca

www.gwnp.ca


#44 slynk   Members   -  Reputation: 144

Like
0Likes
Like

Posted 02 March 2011 - 12:06 PM

It's one thing to question things....


I think this is the first thing you said that I can mostly get behind. ^^ It's really hard to argue this without you knowing the exact circumstances in which I use my method. For example, when on team projects, I follow what ever pattern I'm told to. Obviously you should or it would be a programming nightmare. However, when doing solo projects, I see nothing wrong in my method. For example, I usually inherit player from an animated sprite class in my games. Why? It just make my life easier. It's the way I code. Nothing will ever inherit from player. There's no in between inheritance so why not? I've done small things like pong, to mid size puzzle games, to a full blown link to the past style clone and have *never* ran into an issue. Ever. At least within the context of what we are discussing.

I have been programming for only 9 years and that's still very young for this industry but you have to admit, if I've done so many projects of different sizes then maybe just maybe there can be two methods. Sure yours may be better in your opinion but it's still subjective. To me, if the performance is the same then "better" falls to whom ever's method makes more sense to the programmer.

"What you seem to insist on arguing, is that your one opinion, based on your own limited experience, should call into question the collective work of literally thousands of man-years of insight on these topics."

It only takes one person who sees things differently to define an alternative. ^^

#45 No Style Guy   Members   -  Reputation: 112

Like
0Likes
Like

Posted 02 March 2011 - 01:25 PM

Ravyne's sentiments are applied to general software engineering. Not personal projects.

Since the OP asked for 'best practices in OO', without mentioning a team-size or industry scope, Ravyne made the (correct) choice of illuminating 'best practices for oo in an industry setting'. This is where your "my method has always worked for me" argument falls flat. You openly admit that you could make bad design choices, such as a player class inheriting from an animated sprite class, based on the assumption you'll be the only one who had to extend/understand/maintain the code. You cannot, honestly, believe your approach would be "best practices" in a mature, enterprise sized software system.

My job, as a software engineer for a DOD contractor, entails maintaining code that is literally 20 years old and has hundreds of thousands of lines of code. Unnecessary inheritance is one of the worst parts of understanding this code base, and I'm very grateful most of it is done composition-first.

#46 swiftcoder   Senior Moderators   -  Reputation: 10238

Like
0Likes
Like

Posted 02 March 2011 - 01:34 PM

Player and Enemy should be the subclass of some class if you want to extend to have more than 2 players so they can be stored in a player array or have variable numbers of ai and human players.


Thus why I said they should be subclasses only if they need to present a uniform interface to some client. My broader point is that in the context of Pong, there is no such client, so there is no need for a uniform interface. Were we instead designing 'Pong the MMO', we might have to revisit that distinction...

Tristam MacDonald - Software Engineer @Amazon - [swiftcoding]


#47 slynk   Members   -  Reputation: 144

Like
0Likes
Like

Posted 02 March 2011 - 01:41 PM

You openly admit that you could make bad design choices, such as a player class inheriting from an animated sprite class, based on the assumption you'll be the only one who had to extend/understand/maintain the code. You cannot, honestly, believe your approach would be "best practices" in a mature, enterprise sized software system.


But what makes it a bad design choice? Why does it have to be bad design to bind body and soul into a singular object if that's how you view the world? I mean that's why classes were invented right? To make languages higher level. To give us the ability to describe logical entities as we see fit. If I view the an enemy AI and his body (sprite) as one, who's to say I'm wrong in binding them via inheritance?

#48 swiftcoder   Senior Moderators   -  Reputation: 10238

Like
0Likes
Like

Posted 02 March 2011 - 01:49 PM

If I view the an enemy AI and his body (sprite) as one, who's to say I'm wrong in binding them via inheritance?

The Single Responsibility Principle should be your first clue. Wrapping up graphical representation with logical representation in a single class is only going to lead to trouble down the road.

What happens when you need an enemy AI without a sprite? An enemy sprite without an AI? The same AI with a non-sprite representation? The same sprite rendering attached to a different type of AI?

Tristam MacDonald - Software Engineer @Amazon - [swiftcoding]


#49 No Style Guy   Members   -  Reputation: 112

Like
0Likes
Like

Posted 02 March 2011 - 01:55 PM

You openly admit that you could make bad design choices, such as a player class inheriting from an animated sprite class, based on the assumption you'll be the only one who had to extend/understand/maintain the code. You cannot, honestly, believe your approach would be "best practices" in a mature, enterprise sized software system.


But what makes it a bad design choice? Why does it have to be bad design to bind body and soul into a singular object if that's how you view the world? I mean that's why classes were invented right? To make languages higher level. To give us the ability to describe logical entities as we see fit. If I view the an enemy AI and his body (sprite) as one, who's to say I'm wrong in binding them via inheritance?


By your logic, if i view a game as an object who is a singular object with attributes such as players and terrain and game mechanics and physics, then why not just make one God class that inherits everything from everybody and has no composition? Does that sound like fun to manage?

You're entitled to your view, and in your own one-man-team, you can even make it law, but at the end of the day, you're still relying on people to have the same view as you if you want your code to be easily maintained and extended.

Frankly, composition results in better re-use and maintainability than inheritance by all-but-forcing loose coupling and good cohesion. Inheritance results in less code written, but more tightly coupled, uncohesive code. These are facts, not opinions. The only question is which attributes are more important to you: maintainability, re-use, loose coupling, good cohesion, OR less code written?

#50 slynk   Members   -  Reputation: 144

Like
0Likes
Like

Posted 02 March 2011 - 01:59 PM

What happens when you need an enemy AI without a sprite?

Is he invisible o.O


An enemy sprite without an AI?

Then I just draw the sprite : /

The same AI with a non-sprite representation?

Again, invisible?

The same sprite rendering attached to a different type of AI?

The sprite class I use has a pointer to the image associated with it that has been loaded into memory. It draws that image. It doesn't copy it. So... I'd just give it a copy of the sprite.



#51 way2lazy2care   Members   -  Reputation: 782

Like
0Likes
Like

Posted 02 March 2011 - 02:02 PM

Were we instead designing 'Pong the MMO', we might have to revisit that distinction...


I was thinking 4 possible players (top, bottom, left, and right) who could be either AI, human controlled, or no player (wall). I'd say that's within the scope of a one dude pong clone.

Anyway, I concede that either way works and better-ness depends on how much is planned on being implemented.

#52 slynk   Members   -  Reputation: 144

Like
0Likes
Like

Posted 02 March 2011 - 02:26 PM

By your logic, if i view a game as an object who is a singular object with attributes such as players and terrain and game mechanics and physics, then why not just make one God class that inherits everything from everybody and has no composition? Does that sound like fun to manage?


XD if you view it that way, then go ahead. Personally I think it's much more believable than an enemy "is" both himself (the AI) and his graphical representation (his body) than your extreme. Look, I'm even using "is". That's the problem with the principal. It's opinionated. If I say something IS something and you say something HAS something then people get in this big argument. Just forget the damn principal and program it logically. >.< If you see the player as BEING the paddle, use inheritance. If you see the player as HAVING the paddle, use composition. I don't care.

#53 BCullis   Crossbones+   -  Reputation: 1813

Like
0Likes
Like

Posted 02 March 2011 - 02:37 PM


By your logic, if i view a game as an object who is a singular object with attributes such as players and terrain and game mechanics and physics, then why not just make one God class that inherits everything from everybody and has no composition? Does that sound like fun to manage?


XD if you view it that way, then go ahead. Personally I think it's much more believable than an enemy "is" both himself (the AI) and his graphical representation (his body) than your extreme. Look, I'm even using "is". That's the problem with the principal. It's opinionated. If I say something IS something and you say something HAS something then people get in this big argument. Just forget the damn principal and program it logically. >.< If you see the player as BEING the paddle, use inheritance. If you see the player as HAVING the paddle, use composition. I don't care.


The is-a/has-a confusion here is in part due to the simplistic nature of the game. As the complexity of the object/class population grows, not only will it probably be easier to distinguish clear lines between inheritance cases and composition cases, but composition will beat out an ever-deepening inheritance tree in multiple areas (readability, group-programmer understanding, maintainability, etc).

"Forgetting the principal" and "programming it logically" are at odds...the principal is both logical and time-tested. One can design for both inheritance and composition, the heart of the matter is that your opinion, this programming style that works for you on your own projects, is bad advice for someone wanting to follow good oo practices that scale well into any project.
Hazard Pay :: FPS/RTS in SharpDX
DeviantArt :: Because right-brain needs love too

#54 No Style Guy   Members   -  Reputation: 112

Like
0Likes
Like

Posted 02 March 2011 - 02:48 PM


By your logic, if i view a game as an object who is a singular object with attributes such as players and terrain and game mechanics and physics, then why not just make one God class that inherits everything from everybody and has no composition? Does that sound like fun to manage?


XD if you view it that way, then go ahead. Personally I think it's much more believable than an enemy "is" both himself (the AI) and his graphical representation (his body) than your extreme. Look, I'm even using "is". That's the problem with the principal. It's opinionated. If I say something IS something and you say something HAS something then people get in this big argument. Just forget the damn principal and program it logically. >.< If you see the player as BEING the paddle, use inheritance. If you see the player as HAVING the paddle, use composition. I don't care.


Precisely. My God class example used "is-a" because I was framing it to fit your view. I personally think it makes more sense that "A game has-a terrain, has-a player, has-a Physics system, etc" (as per my exmaple) or even "A player has-a Body (sprite) and has-a Brain (AI)" but you seem to think it should be "A player is-a Body and is-a Brain" (as per your example).

Regardless, I'll conceed that the is-a and has-a idiom can be subjective (or rather, both can work), so I wont argue that further.

The problem is that there are characteristics of each approach that are tangible, undeniable facts. If you have an inheritance tree where the current object has inherited attributes, either directly or indirectly, from, say, 10 different classes, the exact origin, purpose, and usage of those attributes is undeniably confusing. If the same current object was a composition of those classes, it would be (nearly) explicit where those attributes came from, what they affect, and why they're there.

I've lost count of the number of times where I've been trying to extend a class that seems to be modifying an undescriptive member variable (say, "count") which is not declared in the immediate class's header. I then backtrack through each of his multiple inherited base classes for somebody with a "count" member variable. If he had just had MyObject.baseclass.count, I would have had a lot less headaches.

Composition: easy maintainability, re-use, good cohesion and low coupling
Inheritance: less code, but poor {all of the above}

That is the basis for this argument, not opinions about how you view relationships of objects.

#55 slynk   Members   -  Reputation: 144

Like
0Likes
Like

Posted 02 March 2011 - 02:49 PM

"Forgetting the principal" and "programming it logically" are at odds...the principal is both logical and time-tested. One can design for both inheritance and composition, the heart of the matter is that your opinion, this programming style that works for you on your own projects, is bad advice for someone wanting to follow good oo practices that scale well into any project.


My original advice was to inherit the player class from the paddle class as I view the player as pretty much being the paddle in this instance. This debate then started when someone quoted oo principal as a means to debunk my method when in fact it followed the said principal. So how was it bad advice? And how does it not scale? If someone views something in a large scale project as being something, doesn't your principal teach that they should use inheritance?

I'm done, you're all right. There can be one and only one way to do things. I give up. Posted Image

EDIT: "from, say, 10 different classes" I wouldn't know I never use more than single inheritance :o

#56 way2lazy2care   Members   -  Reputation: 782

Like
0Likes
Like

Posted 02 March 2011 - 03:00 PM

I'm done, you're all right. There can be one and only one way to do things. I give up. Posted Image

EDIT: "from, say, 10 different classes" I wouldn't know I never use more than single inheritance :o


There are tons of ways to do things. There are much fewer ways to do things well. I could walk home every night by first flying to New York and then walking the couple hundred miles back, but that would be inefficient. There are however a couple routes home that are practically the same distance and walking time.

A good counter example to your thing would be having a player with a sprite and a physics object and AI. Does he inherit from sprite? Does he inherit from his physics object? Does he inherit from AI? Not all languages support multiple inheritance, and there's no reason a sprite should also be a physics object or AI or any other order.

Bad design can make sense in small games, but even on a one person game as complexity grows you will find these OOP principles come into play a lot more because eventually you will either be wasting tons of memory space/clock cycles or just won't be able to get your objects to work as desired.

#57 Hodgman   Moderators   -  Reputation: 31056

Like
5Likes
Like

Posted 02 March 2011 - 09:11 PM

I'm done, you're all right. There can be one and only one way to do things. I give up. Posted Image

Stop acting like such a victim - no one is saying there's "only one way to do things"!
There's nothing wrong with your methods when scrutinised outside of the field of OOD. Stop trying to shove your opinions down our throats, and stop labelling formal systems as opinions. Stop being so narrow minded and go and study the things that you're dismissing to find out for yourself why/if they have value before you go ranting about how your sophomoric seat-of-your-pants methods are superior to OOD - we don't care, it's not relevant to the thread.

OOD is a group of formal design methodologies, which, contrary to your continued assertions, do allow for an objective view on whether a design is "good" or "bad".
That is the entire point of creating formal systems - to get away from subjective feelings about things. The formal system isn't necessarily right or wrong, it just gives us self-consistent objective measurements.

If we step outside of this methodology for a moment, then yes, you can assert your opinion that the methodology isn't important (meaning it's objective descriptions are also unimportant) --- but that's completely irrelevant when the discussion is supposed to be taking place inside of these principles/methods.

Personally I think it's much more believable than an enemy "is" both himself (the AI) and his graphical representation (his body) than your extreme. Look, I'm even using "is". That's the problem with the principal. It's opinionated. If I say something IS something and you say something HAS something then people get in this big argument.

You keep repeating this assertion that the choice is simply an opinion -- which is absolutely wrong. The formal methodology lays out objective rules that guide this choice - there's no opinion involved.

The fact is, that when evaluated using the principles set out in these methods, your design violates quite a few rules, making it as a "bad" design.

You're right in that a perfectly usable design may in fact fail these tests --- but that's completely irrelevant when the discussion is supposed to be taking place inside of this methodology

But what makes it a bad design choice?

You've been told repeatedly of the OOD rules that the design violates... Therefore inside the field of OOD, it's not a good choice. You're free to evaluate it outside of the field of OOD --- but that's completely irrelevant when the discussion is supposed to be taking place inside of the field of OOD.

Why does it have to be bad design to bind body and soul into a singular object if that's how you view the world? I mean that's why classes were invented right? To make languages higher level. To give us the ability to describe logical entities as we see fit. If I view the an enemy AI and his body (sprite) as one, who's to say I'm wrong in binding them via inheritance?

Classes as a language feature were invented so that OOD could easily be written via OOP.
OOD says that you're wrong in making that decision (as said before, AI "is a" Sprite violates OOD rules). You're free to ignore OOD and trust your own intuition --- but that's completely irrelevant when the discussion is supposed to be taking place inside of the field of OOD.

#58 slynk   Members   -  Reputation: 144

Like
0Likes
Like

Posted 02 March 2011 - 11:07 PM

As stated, I refuse to argue the matter further, why beat a dead horse? Do you really think it's a mature thing to do? Do you really believe it's mature to claim some one is acting the victim? Your hostility, name calling, and sarcasm have been completely unwarranted. Get off your high horse, recognize that I have made SOME valid points and A LOT of not so valid ones. The user above you succeeds the the fact that when deciding whether something IS-A or HAS-A is completely subjective (although usually obvious). There's no reason for you to be so obtuse. If you can't handle a mature debate, don't participate in one. It's easy to debate. Assert your opinion, provide evidence to support your opinion and provide couter points to the other's arguments. Difference of opinion != hostile intent. ^^

#59 Hodgman   Moderators   -  Reputation: 31056

Like
0Likes
Like

Posted 02 March 2011 - 11:25 PM

I'm not a kettle!

#60 SimonForsman   Crossbones+   -  Reputation: 6174

Like
4Likes
Like

Posted 03 March 2011 - 01:33 AM

As stated, I refuse to argue the matter further, why beat a dead horse? Do you really think it's a mature thing to do? Do you really believe it's mature to claim some one is acting the victim? Your hostility, name calling, and sarcasm have been completely unwarranted. Get off your high horse, recognize that I have made SOME valid points and A LOT of not so valid ones. The user above you succeeds the the fact that when deciding whether something IS-A or HAS-A is completely subjective (although usually obvious). There's no reason for you to be so obtuse. If you can't handle a mature debate, don't participate in one. It's easy to debate. Assert your opinion, provide evidence to support your opinion and provide couter points to the other's arguments. Difference of opinion != hostile intent. ^^


If you refuse to argue the matter further why are you still replying to posts ?

Looking through through the posts i only see one poster who doesn't handle a mature debate very well and who has effectivly derailed this thread.

While it is true that the distinction between "is a" and "has a" can be muddy it usually isn't.

you might get away with arguing that this is a good design
class Person {
....
}
class Developer: public Person {
....
}
While it is true that a developer is a person something like:
class Occupation {
....
}
class Developer: public Occupation {
....
}
class Person {
private:
std::vector<Occupation> occupations
......
}
would be a better option since it moves generic occupation information out of the Person class (an unemployed person doesn't need those) and you could give a person multiple occupations (By adding work hours to the Occupation base class this design would allow you to easily create for example a student who works at 7-11 on friday and saturday nights while with the inheritance approach you'd have to create a new subclass for each combination).

Basically composition is more flexible than inheritance so if you're in a position where you can choose between them the composition route is almost always better.
(One can ofcourse take it further and cut out the inheritance for the Occupation class aswell and compose the Occupation class using things like job titles, tasks, etc which would make things even more flexible)
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!




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS