I asked why, but still haven't received an answer. Do you see a problem with these interfaces? If so, how would you fix it, and still keep the same functionality provided in the answer?These interfaces should not inherit from each other.
Would it be the simplicity of the GameObject and the fact that the function it provides is unnecessary?
This goes back again to Andy Hunt's rule #1: Always consider context.
It seems like you read Bloch's advice to prefer programming to interfaces and thought, "Ok, let me make everything in this program an interface." The advice said to prefer, it didn't say always. The advice was meant to be applied in context. You seem to be using it like it's a context-free rule.
I haven't seen the rest of your program, so I have no context with which to base a yea or nay vote on interfaces here but I think you would make it easier on yourself to curb your enthusiasm and go with a simple, if naive, design first and learn some lessons from what the code really wants to be.
I told you before that your code should tell a story. You should also listen to your code when you write it. If it is too convoluted, it wants to be clarified. When it's too brittle, it wants to be teased apart and the couplings made looser, so it's more flexible. When it's too complex, it wants to be simplified. The abstraction that interfaces provide can be useful and even desirable but it also comes with an additional layer of indirection and therefore, more complexity. It seems to me your code is saying it's too complex.
Does that make sense?
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
if naive, design first and learn some lessons from what the code really wants to be.
Let me explain why I chose to use interfaces.
Weapon is ambiguous, now, you could make it an abstract class, which is what I did before, I had a constructor that took the name and damage, and had an abstract method attack. Looked good, but wait! Let's say I had to subclass Gun, now depending on the complexity of my game, this would be fine, but let's think about this, Gun itself is a little ambiguous(let's make it abstract), is it a handgun or rifle? Both have a different set of behaviors before firing to make a successful shot, and both have different attachments(rifle has a scope, but both can have silencers, laser sight, etc). We add two more subclass to accommodate both types of Gun.
Now we have Weapon(abstract) > Gun(abstract) > Handgun,Rifle
This is getting messy and as many articles point out, a deep inheritance hierarchy should be avoided. Depending on my game environment, I might have a rifle different from the conventional type of rifle(think Unreal tournament), with it's own set of attributes/behaviors, distinct enough for another subclass.
Now, if I made Weapon an interface, and Reloadable an interface, I have a little more freedom. I create the final class HandGun and implement both interfaces without worrying about how deep the inheritance goes, same for rifle.
It seems to me your code is saying it's too complex.
My code was too complex. For me interfaces made it simpler.
Now consider this, Gun probably shouldn't be named Gun, what if I also wanted a bow and arrow, it's reloadable every time you take shot, and again different behavior than a Gun.
Which means this Weapon > ReloadableWeapon > Guns > rifle/handgun
ReloadableWeapon > Bow and Arrow
Let's look at another problem,
Again, with Weapon(Abstract) > Sword(abstract) > Simple Sword, Fire Sword, and FireTransportSword.
Let's say sword split into two other swords, simple sword i can only do swing attack(nothing more, nothing less). Now let's say I have a fire sword, it can swing, the blade has a fire I can control, and can shoot fireballs. If Java allowed multiple inheritance, then having FireTransportSword extending Simple Sword and Fire Sword would create the diamond problem, both Simple Sword/Fire Sword override attack and implement it in different ways, how would FireTransportSword(A sword that has the same attributes and attack as simple and fire sword, but it also allows me to cut a hole in space/time to suck enemies into a black hole) implement attack?
I could make Sword and Transport and interface(also allowing other objects to implement transport in there own way), and using the weapon interface, create my swords without the diamond problem. I can even be more flexiable with my swing, I can swing and shoot fireballs at the same time.
To me interfaces made it simple, and made sense. What makes sense to you? How would you do it?
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
Hank Emery wrote:To me interfaces made it simple, and made sense. What makes sense to you? How would you do it?
You're misunderstanding where interfaces can add complexity. Yes, they make your abstractions and high-level ideas simpler. However, the simplicity gained in the high-level abstract is paid for by added complexity in the underlying implementation details.
I was looking at your design in the other thread and your problem there was that every time you added a new GameObject, you were afraid that you were going to have to change your Character interface to accommodate it.
Everytime I have a new GameObject the player can interact with, I would have to update my Character interface with pickup/use methods. The problem with this is, a GameObject sometimes can be used in different ways.
That's a design smell and you seem to recognize it. Your problem is that you don't know what to do now. Here's a hint: when you find yourself saying things like "can be used in different ways" and you detect a smell, that means you need to find another abstraction so that you can treat different things similarly. And this is where you'll see yourself paying for the simplicity you had in a higher level of abstraction.
I'm actually working on a book with a core theme of thinking backwards. You are stuck because you want to find a way to solve your problem by looking at it from the perspective you have now. Most people will try to force that perspective and try to bend and twist their design to fit their perspective. Code and design has a way of fighting back and it's seldom the programmer who is the winner. However, I suspect that if you change your perspective and not think from the perspective of "all the different ways the character can use a weapon" but instead think of "how a game object can benefit the character" this will probably lead you to a more stable Character interface and abstraction. After all, any weapon the character uses can be used to inflict damage on an opponent, no matter what kind of weapon it is. A weapon used by an opponent on your character will also inflict damage, but this time on your character.
When damage is inflicted, your character's health is affected. When a character uses a healthpack, again it's health is affected. So, when you think of it backwards and ask "How does this GameObject benefit the Character" you'll probably find that there are a limited number of ways that a Character can benefit from anything. Now you can provide a consistent, stable interface for your Character so that whatever thing he picks up, that thing can "know" how it benefits the Character.
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
EDIT: This was a great validation of the point I made earlier. I don't play video games any more because all these new video games give me motion sickness. The last video games I remember playing with my son were four or five game consoles ago, on a Nintendo 64 playing Donkey Kong and Star Wars. If my son says being able to view how an object affects a character's stats is a feature of literally every video game, I'll take his word for it. That just tells me that what you have is a common problem that has a known solution that is most likely very similar to what I described.
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
What about the Reloadable interface, why does it have a replenish() method instead of reload()? Doesn't the latter make more sense? I've never heard a shooting video game in the arcade prompt you to "Replenish!" when your magazine is spent; they always tells you to "RELOAD!"
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
Junilu Lacar wrote:With this fresh perspective in mind, look at the interfaces you defined again. Does a weapon really attack? Who does the attacking, the character or the weapon? Doesn't it make more sense to say that it's the Character who's attacking another Character with a weapon? How does that change of perspective change the way your objects interact with each other and how your code is written?
The character does the attacking, this is why I rewrote my interface to accommodate this. The character uses a weapon to attack with.
Side Note: This game is a hobby project, in the beginning stages. It's constantly going to get rewritten, and tested, and finished when it's finished.

What about the Reloadable interface, why does it have a replenish() method instead of reload()? Doesn't the latter make more sense? I've never heard a shooting video game in the arcade prompt you to "Replenish!" when your magazine is spent; they always tells you to "RELOAD!"
While this is true, a container could also be reloaded, although you don't say reloaded, you say refilled, different words for the same behavior. The Reloadable interface could be applied to potion bottle, health bar, and weapons etc.
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
Hank Emery wrote:
Reading your code out loud also helps you detect problems in the semantics of your design. How are you reading that method signature? To me, it reads "A character uses a weapon to attack with an enemy." That's a very awkward sentence and it doesn't make much sense. First, try to say your intent in plain English: "I want the Character to attack its enemy Character using a particular weapon." This leads you to write the code that you want to write:
Or something like that. I like to think of this as "listening to what code wants to be".
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
Junilu Lacar wrote:
Hank Emery wrote:
This is still smelly. If you design it this way, your interface will not be stable until your imagination becomes stable and runs out of different things to add to your inventory. Again, when you hear yourself saying "I need to handle different things" and you smell instability in your interface, you need to find the commonality in those different things and abstract them away so that your interface only deals with what's common and your implementations handle the details of what's different in each of them.
How would you fix the character interface? This is what I have so far:
Hank Emery wrote:
How would you fix the character interface?
I already went over that in excruciating detail over the weekend. Maybe my long-winded response was too much to read? In short, I would change my perspective and try to make a stable interface for Character that is based on the common things that it can benefit from by interacting with different objects. Things like increasing health, agility, attack power, defenses, wealth, etc. Those are all inherent to the Character. I would move the responsibility of knowing how a Character's attributes are affected to the different things that have influence in changing, increasing, or decreasing one or more of these Character attributes.
Edit: On second thought, maybe the details were too excruciating or maybe they were just detailed in my mind and I didn't express myself in a way that you could see what the details were. I wouldn't blame you if your eyes glossed over reading what I wrote over the weekend. My apologies for being snippy there.
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
I wrote:Your backwards brain is what ... keeps you thinking more about the implementation details and less about the intent."
The names you chose for your parameters are signs that your backwards brain is hard at work. "enemyObj", "reloadObj", "reloadadd", "gameObj", "Reloadable vs ReloadableWeapon", all these names have one thing in common: They reveal your implementation-focused mindset. Why tack on "Obj" to those names? Everyone reading your code will know those are objects, so why do you feel you need to constantly remind them? Or is this your way of making your code self-documenting? If it is, it's not a good practice. Well, self-documenting code is a good practice but tacking on a useless prefix or suffix wart like "Obj" isn't. Charles Simonyi regrets how his Hungarian notation was misused over the years and turned into a meaningless convention because of mindless, rote, and uninformed use. Tacking on "Obj" to the name of something that is clearly an object is going down that same path to uselessness. It's like me calling you HankMale or HankPerson.
Here's another smell: When your method name has the name of another entity. The name addItemToInventory not only reveals a mindset focused on implementation (you know that your Character has an inventory because you just announced it with your method name), it also hints at a misplaced responsibility. Is the logic in this method going to show the details of adding an item to the Character's inventory of things? Why? Shouldn't the details of that operation be encapsulated in an Inventory object? Why isn't that method just called pickUp(Item whatever)? This way, it will be more abstract. Who cares how the Character handles that item internally after he has picked it up? Nobody does, at least not at this level of abstraction.
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
In my game I have a variety of weapons with the following interface:
Not every weapon is reloadable, for example swords, so they must be applied accordingly.
I have the following class:
I now store it in it's own collection like so:
I also have close quarters weapons (swords, knives, etc..)
Problems:
1. I could store all my weapons in a List<Weapon>, problem is I wouldn't have access to the replenish() method if I do.
2. Creating a List collection for every Weapon type
I think the question will give you a different perspective as well, or at least widen your current perspective. It's relevant to your inventory of things and how you might be able to create a flexible design that takes advantage of Java's type system, or work around its limitations.
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
Hank Emery wrote:
In my game I have a variety of weapons with the following interface:
Not every weapon is reloadable, for example swords, so they must be applied accordingly.
...
This is what I was referring to as going hog wild. I think you should definitely curb your enthusiasm, put your imagination on a leash, and just implement one weapon first. It's far more difficult to juggle several different, untested, and nebulous ideas in your mind than it is to have just one bouncing around in there. When you have your idea written down as code and a testable design, then you can learn from it. Working software is the best way to learn about what your code and design wants to be, even if your software isn't fully working or designed the best way yet. You still learn from it. If not what it should, at least you'll learn what it shouldn't be. It's like my wife going shopping. She'll often just go to the store not knowing what she wants. She'll look at different things and try them on. As she does that and moves on the next thing, she slowly gets a better idea of what she's actually looking for. Of course, what she's looking for is always the last thing she sees, right?
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
Junilu Lacar wrote:You might want to read this thread: https://coderanch.com/t/679568/java/feature-exist-returning-downcasted-object
I think the question will give you a different perspective as well, or at least widen your current perspective. It's relevant to your inventory of things and how you might be able to create a flexible design that takes advantage of Java's type system, or work around its limitations.
Casting is fine, but, this means, I will have to use the instanceof operator, outside of the equals method, isn't it bad practice?
My idea last night was that a GameObject might respond to a query, specifically, as part of a call in a Predicate, that determines whether or not it has some capability. I think Bloch actually writes about better alternatives to instanceof in his "Effective Java" book.
If a GameObject had this method:
You might be able to use one of the methods of Class: https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html like isInstance() or isAssignableFrom() to filter it from a list using a Predicate.
Not using instanceof is another one of those "rules" that you have to take in context. In most cases where polymorphism is not properly used, instanceof is a smell. In other cases, like in a framework that needs some extra flexibility that polymorphism might not be able to provide, then it may be acceptable and even appropriate to use. Again, the trick is knowing the difference.
Practice only makes habit, only perfect practice makes perfect.
Practice mindfully by doing the right things and doing things right.— Junilu
[How to Ask Questions] [How to Answer Questions]
