Hank Starmoon wrote:If the player begins a new game, he/she may not have a weapon to start off with or if I create a class called NPC that implements the Character interface, the NPC may have a game object(ex. coins, potions), but no weapons.
Carey Brown wrote:
Hank Starmoon wrote:If the player begins a new game, he/she may not have a weapon to start off with or if I create a class called NPC that implements the Character interface, the NPC may have a game object(ex. coins, potions), but no weapons.
It sounds like you may have more than one weapon or object. In that case I'd suggest a List and if there are none, then return an empty List.
Hank Emery wrote:1. Is what I do in the constructor(creating the arraylists) instead of passing it in as a parameter, okay?
2. Are the add/remove methods okay to have? Is there a better way of doing it?
Carey Brown wrote:
Hank Emery wrote:1. Is what I do in the constructor(creating the arraylists) instead of passing it in as a parameter, okay?
2. Are the add/remove methods okay to have? Is there a better way of doing it?
1. Yes.
2. Add/remove is the better way.
In general, you're on the right track, but you have some syntax errors that would keep it from compiling.
Curious: why "gameWeapon" vs just "weapon" ?
Junilu Lacar wrote:An interface that defines only getter and setter methods is smelly. An interface should be a contract for behavior or capabilities. The only thing that your interface says its implementations can do is to be told what its attributes are and to be told to share its attributes, so you probably don't have a very good understanding of what object-orientation is about. This interface basically sets up its implementations to have their encapsulation broken from the moment they come into existence.
Defining an interface also says that your design doesn't care about the object hierarchy of the implementation. It says, "As long as you can behave in these ways (the behavior/capabilities that the interface methods specify), you will be treated as such and such." It's like saying "It doesn't matter what your background is, whether rich or poor, formally educated or self-educated, of nobility or of the gentry, as long as you behave like a gentleman and a scholar, then you will be treated and afforded the office and due deference as such."
Hank Emery wrote:Just a small clarification, when you say Add/Remove is better? You mean like this ?
Hank Emery wrote:How would you then restructure this?
Junilu Lacar wrote:Notice that I previously said, "I'd have to go an experiment with a Character that is defined like this."
That's because when you start out with a design, your ideas about how everything works together is very vague and nebulous. You have to write code to see exactly what it looks like "on paper" instead of just in your head. Ideas seem far better when they're just floating around in our heads. It's only when you put those ideas into code and can actually SEE the design as code that your are able to (if you have trained yourself enough) see all the little flaws and gaps that your brain was somehow filling in or ignoring altogether.
Again, this is why I am a firm believer in Jack Reeves' propositions that Code is Design.
(Edit: I said "Again" but if I didn't mention Jack Reeves before in this thread, I must have done it in a post I made today in a different thread).
Junilu Lacar wrote:And to show I can be direct to the point as much I can be long-winded...
What's wrong with just writing this?
Carey Brown wrote:Id, first, and last should all be fields of Student and the getters/setters for them should also be in Student.
Hank Emery wrote:I understand I violated what you just explained when it comes to naming conventions, but it's the only way I could explain my problem.
Hank Emery wrote:
Let's say if I have a method that displays student number regardless of student type,
Junilu Lacar wrote:
Hank Emery wrote:I understand I violated what you just explained when it comes to naming conventions, but it's the only way I could explain my problem.
Don't take any of my comments about getters and setters violating encapsulation turn into an indictment of those kinds of methods. You have to balance it out. Go back and see where I said something along the lines of "You have to be careful... if you define getters and setters right off the bat and start writing your code and formulating your design around these methods, then you're probably thinking the opposite way of how you need to be when writing object-oriented programs."
In other words, don't let getters and setters be the central focus of your design. If possible, use them only for display purposes. There's another school of thought, or at least experimentation, where you go to the extreme of sticking with encapsulation that you do things like this:
It's not difficult to imagine what the student.displayId() method looks like. Sure, this looks like you've preserved encapsulation and it certainly is an interesting exercise to try to write a lot of code like this. I've done it and it gets to be a pain in the neck. So yeah, I use getters when I need to display things. I'm not crazy dogmatic about object-orientation. But I do find that trying to stay true to the principles does help me a lot as well. You just have to know when it's OK to bend the rules a little bit.
Junilu Lacar wrote:
Hank Emery wrote:
Let's say if I have a method that displays student number regardless of student type,
Andy Hunt's Rule #1: Always Consider Context.
Where is this code located? What is the larger picture that this code operates within? What's the difference between an International student and a Domestic student and how is that significant to viewing their IDs?
I could certainly imagine something like this (maybe) being a valid responsibility of some class:
It's hard to give an answer to a question where the context is unknown or left to the imagination. So, again, what's the bigger picture of what you're trying to achieve by displaying a Student's id?
Hank Emery wrote:
It's going to take some practice, and patience, but I think I'm getting it. How did you come to learn all of this? Years of experience, or school? I "learned" Java in school but never came across what you just demonstrated. There is another thread talking about how universities aren't properly teaching programming, and after what I've seen, and been through, I agree. I used learned in quotes, as they brushed past important topics, and even violated proper practices without any mention. It's only after reading Effective Java that I learned my professor where making mistakes and teaching it as if it was normal. This to me is wrong, and your sending students out into the real world thinking they know how to write proper code. I've seen a professor overwrite the equals method and do everything Effective Java warns against! She didn't even mention this was incorrect. Effective Java wasn't even on the reading list, I found it on Amazon, and after seeing recommendations on SO, I bought it(a quality buy, too!).
Junilu Lacar wrote:Practice doing the right things and doing things right.
Hank Emery wrote:My whole point/question is, when it makes sense, it's okay to have getters/setters in the interface correct? but don't get carried away and have that be the only reason why I'm using and interface(just to have getter/setters)?
Junilu Lacar wrote:
Hank Emery wrote:
It's going to take some practice, and patience, but I think I'm getting it. How did you come to learn all of this? Years of experience, or school? I "learned" Java in school but never came across what you just demonstrated. There is another thread talking about how universities aren't properly teaching programming, and after what I've seen, and been through, I agree. I used learned in quotes, as they brushed past important topics, and even violated proper practices without any mention. It's only after reading Effective Java that I learned my professor where making mistakes and teaching it as if it was normal. This to me is wrong, and your sending students out into the real world thinking they know how to write proper code. I've seen a professor overwrite the equals method and do everything Effective Java warns against! She didn't even mention this was incorrect. Effective Java wasn't even on the reading list, I found it on Amazon, and after seeing recommendations on SO, I bought it(a quality buy, too!).
Yes, I am coming up to almost thirty years as a professional developer. So I've seen a lot of... well, let's just call it "stuff"... that's just totally messed up. The thread you are alluding to is probably one that I started or am heavily commenting on.
I actually just got back from doing a workshop on trying to figure out how to better align academia and industry because you're right, I do see a lot of schools getting so far behind current industry practices that I'm actually starting to believe Robert "Uncle Bob" Martin's dire prediction that the 50% of the total developer population in the world that has less than 5 years of experience is a dire portent of a disaster or series of disasters that is/are bound to happen in the next few years. Go out on YouTube and watch "Uncle Bob - Future of Programming" - he talks about this impending disaster somewhere in the last 18 minutes of this presentation. I'd encourage you to watch the entire presentation though because Uncle Bob's talks can be quite entertaining as they are educational.
I'm glad there are students like you who think critically and who go out and search for information to supplement what they are learning in the classroom. It's important that you stay in touch with the real world because as far as what I have seen, most professors don't. In fact, the professors I collaborated with at the Charleston Southern University were the first ones to express these same concerns and do something about it with me. Others I have tried to reach out to in other universities were not so open-minded.
You have to start somewhere though and if I can make a little bit of difference to one or two people, my hope is that they will be compelled to make a difference for another two or three people as well. Hey, we're computer folks. We should know how exponential growth works, right?
So, yeah, practice. And practice A LOT.
How do you get to Carnegie Hall? Practice, Practice, Practice!
But practice mindfully because... "Practice only makes habit; only perfect practice makes perfect."—Every music teacher, ever.
So,
Junilu Lacar wrote:Practice doing the right things and doing things right.
Hank Emery wrote:... meaning our method would take the list, generate the attendance list of 20 students and write that new attendance list to the database
Hank Emery wrote:How did you come to learn all of this? Years of experience, or school? I "learned" Java in school but never came across what you just demonstrated.
Junilu Lacar wrote:One thing I've learned through experience and experimentation is to not go hog-wild about using interfaces. Everything in moderation. Having a Student type defined as an interface might be a bit much. Right now, my heuristic is to use interfaces at system/layer/architectural boundaries. This helps me keep layers relatively decoupled. Within a layer, there's not much need to use interfaces to put a level of indirection and decoupling between classes. If classes are all in the same layer, let them "know" about each other on a more intimate level. Interfaces put a lot of "distance" between types by hiding as much implementation details as possible. When this kind of abstraction is justified, it's a good thing. When it gets too much, it adds unnecessary complexity, which should be avoided.
So, should Student be an interface if you're just trying to do the things you described? I would lean towards, "probably not."
Hank Emery wrote:Small question, let's assume our game is really simple, if we add the methods increacehealth/decreasehealth to our character interface, and had a Weapon interface, now a weapon would obviously cause damage to our character. How would you create a weapon interface(cause our game can have more than one weapon that share the same attributes), and get the damage that weapon causes to deplete our character health? As you said getters/setter are code smell, so a getter like getWeaponDamage(); isn't considered proper practice. What would you do in this case?
Junilu Lacar wrote:
Hank Emery wrote:Small question, let's assume our game is really simple, if we add the methods increacehealth/decreasehealth to our character interface, and had a Weapon interface, now a weapon would obviously cause damage to our character. How would you create a weapon interface(cause our game can have more than one weapon that share the same attributes), and get the damage that weapon causes to deplete our character health? As you said getters/setter are code smell, so a getter like getWeaponDamage(); isn't considered proper practice. What would you do in this case?
Method names like increaseHealth() and decreaseHealth() are smelly because they have a data focus. Increasing or decreasing the health of a Character happens as a consequence of some event or action that involved the Character. So I would look to that event or action and try to see what can be done inside the methods that handle the event or action to automatically increase or decrease health, without any external entity saying "Increase your health, Character, by this much!" or "Decrease your health, Character, by this much!"
I would probably think, when does my Character's health increase? When does it decrease? If a Character's health increases when you call its rest() or recover() method or it somehow gains health by killing its opponent as a result of you calling strike(Character other), then this is something that I might try:
You can probably guess in which methods each Character object's health is actually increased and decreased, right? Nobody external to the Character object had to manipulate its health levels. The Character object does that as a result of finishing off its opponent. The opponent, on the other hand, gives out the information about how much health it had left after setting its own health to zero when its finishOff() method gets called.
Do you see how this kind of code tells a story? It's not some "godlike" programmer inserting his thoughts into the commands and manipulating object properties through program commands. It's just objects encapsulating logic that makes them behave like their own animate and sentient things. That's the magic that happens when you write programs like this. Your thoughts come alive in the program even as they leave your head and get encoded in 1s and 0s in the computer.
Junilu Lacar wrote:And don't forget what I said before: Ideas that float around in your head seem better than they actually are than when you actually see them "on paper", i.e., in actual code.
Take what I just suggested:
That might not be quite right either. Why am I passing the absorbHealth() method the result of calling opponent.finishOff()? Would it be more clear and abstract if I wrote this instead?
Do you see what I changed? That means I eliminate the absorbHealth() method and have this instead:
I still have a pretty good story going on here, right? I would read that as "When I finish off this other Character, I make it relinquish all its remaining health and I absorb that health into myself"
Those two methods are simply:
Still a pretty good story in this code, right?
Junilu Lacar wrote:With your ChargeGun example, I'm not so sure I'd do it that way. The semantics of that stuff happening in the ChargeGun class doesn't seem as natural as they would in a Character. I might try to see what the commonalities are between different weapons and try to find an abstraction to represent their usage. I probably wouldn't care too much about the semantics of methods names strike() versus shoot() versus stab() or slice(). I tend to use those names only to find what the abstraction is that I'm really looking for. For example, given all those different ways of using a Weapon, I might end up refactoring the method to this instead:
Or something like that. Make sure to read your code over and over, forgetting everything you were thinking about before and come at the code as though you were someone else seeing it for the first time. Does it make sense? Is the story coherent? Do the object actions make sense? Do the method names reveal the intent? The variable names, do they reveal their intent? Do they add richness to the story you're trying to tell with this code?
That's basically my thought process when I try to critique my code.
Junilu Lacar wrote:Here's another reason I'd resist putting that logic in a class like ChargeGun. What do you do in other Weapon classes? What you'll probably end up seeing is a lot of duplicated logic. Another principle of good software is DRY, or Don't Repeat Yourself. DRY is about duplicated ideas/knowledge/behavior, not duplicated characters/letters, as most people might think. If each Weapon's "attack"-type method, slice, shoot, stab, poke, whatever, had to the same kind of logic that said:
then this would be a violation of DRY. You'd want to have that logic in one place only so that if you have to change it, it would only have to be changed in that one place. Duplicated knowledge/ideas/behavior makes you do more maintenance work than you should have to and it's a source of bugs that make your program's behavior inconsistent or just plain wrong in some parts while it's correct in others (indicating that you forgot to update one or more duplicated parts).
Junilu Lacar wrote:Here's another reason I'd resist putting that logic in a class like ChargeGun. What do you do in other Weapon classes? What you'll probably end up seeing is a lot of duplicated logic. Another principle of good software is DRY, or Don't Repeat Yourself. DRY is about duplicated ideas/knowledge/behavior, not duplicated characters/letters, as most people might think. If each Weapon's "attack"-type method, slice, shoot, stab, poke, whatever, had to the same kind of logic that said:
then this would be a violation of DRY. You'd want to have that logic in one place only so that if you have to change it, it would only have to be changed in that one place. Duplicated knowledge/ideas/behavior makes you do more maintenance work than you should have to and it's a source of bugs that make your program's behavior inconsistent or just plain wrong in some parts while it's correct in others (indicating that you forgot to update one or more duplicated parts).
Did you see how Paul cut 87% off of his electric heat bill with 82 watts of micro heaters? |