[java] Abstract and concrete classes. Rock, Paper, Scissors

Started by
6 comments, last by CaptainJester 14 years, 4 months ago
Hi all im trying to make a simple rock paper scissors game to get a grasp of abstract and concrete classes. I asked a lecturer of mine to set me this task and I think iv almost got it but am having a little trouble understanding one thing thats going wrong and im a total newbie with java. Here's what i have so far:

	import fuchimi.Hand;
	import fuchimi.Paper;
	import fuchimi.Rock;
	import fuchimi.Scissors;
	
	public class FuChiMi {
		public static void main(String[] args) {
			Hand hand1 = new Rock() ;
			Hand hand2 = new Paper() ;
			Hand hand3 = new Scissors() ;
			System.out.println(hand1 + " beats " + hand1 + "? " + hand1.beats(hand1)) ;
			System.out.println(hand1 + " beats " + hand2 + "? " + hand1.beats(hand2)) ;
			System.out.println(hand1 + " beats " + hand3 + "? " + hand1.beats(hand3)) ;
			System.out.println(hand2 + " beats " + hand1 + "? " + hand2.beats(hand1)) ;
			System.out.println(hand2 + " beats " + hand2 + "? " + hand2.beats(hand2)) ;
			System.out.println(hand2 + " beats " + hand3 + "? " + hand2.beats(hand3)) ;
			System.out.println(hand3 + " beats " + hand1 + "? " + hand3.beats(hand1)) ;
			System.out.println(hand3 + " beats " + hand2 + "? " + hand3.beats(hand2)) ;
			System.out.println(hand3 + " beats " + hand3 + "? " + hand3.beats(hand3)) ;
		}
	}
-------------------------------------------------------------------------------
package fuchimi;

public abstract class Hand {
	
	public abstract boolean beats(Hand hand);
	
	protected abstract boolean loseAgainst(Rock rock);
	
	protected abstract boolean loseAgainst(Paper paper);
	
	protected abstract boolean loseAgainst(Scissors scissors);
}
--------------------------------------------------------------------------------
package fuchimi;

public class Paper extends Hand{
	
	public boolean beats(Hand hand) {
		return loseAgainst(hand); <----TROUBLE HERE!!!!
	}

	protected boolean loseAgainst(Rock rock) {
		return true;
	}

	protected boolean loseAgainst(Scissors scissors) {
		return false;
	}
	
	protected boolean loseAgainst(Paper paper) {
		return false;
	}
}

At the moment I just want the correct statements to be printed. Oh and I obviously have Rock and Scissor classes but they are evidently more or less the same as the paper class. Now my lecturer says not to use any type casts, switchcase or if-then-else structures. I am to use the way the methods are chosen at runtime. How do I implement this as java does not like what I have done? What I am getting is 'The method loseAgaint(Rock) in the type Paper is not applicable for the arguments (Hand)'. Any help much appreciated!
Advertisement
What you are doing here is called double dispatch.

Give that article a read and see if you can correct the line you're having trouble with. (I don't want to give the answer outright :])

Not sure why you got set this for getting a grip on abstract/concrete classes, but hey.
Actually mattd already answered it but hey :)

You already know which line is wrong. The problem is that you are trying to pass a superclass to a function that expects a concrete subclass. Every subclass is an instance of its superclass but not every superclass is an instance of all its subclasses. Consider that hand could be anything that subclasses the Hand class, for instance a BigSweatyHand which extends Hand and is therefore not related to Rock, Paper, or Scissors - Java wouldn't know which loseAgainst() method to call, since none are applicable.

However, there is a way to make this work by only changing one line in each of your concrete subclasses. Think about who exactly knows about at least one of the Hands' concrete subclass, and the answer should come naturally.
Hi guys, thanks for all the help.sorry I havnt replied sooner. Iv read through that link and im pretty sure I get it but im having trouble applying it to my own needs.
Hold on... could this be the answer?
package fuchimi;public class Paper extends Hand{		public boolean beats(Hand hand) {		return hand.loseAgainst(this); //<------AMMENDED LINE	}	protected boolean loseAgainst(Rock rock) {		return false;	}	protected boolean loseAgainst(Scissors scissors) {		return true;	}		protected boolean loseAgainst(Paper paper) {		return true;	}}
That will solve the problem sort of. But your real problem is that a parent class should never know what classes are sub classing it. Hand should not know or care that Rock, Paper and Scissors exist.
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][LWJGL Tutorials for NeHe][LWJGL Wiki][jMonkey Engine]
Quote:Original post by CaptainJester
That will solve the problem sort of. But your real problem is that a parent class should never know what classes are sub classing it. Hand should not know or care that Rock, Paper and Scissors exist.


I agree with this, but what is the answer? The double dispatch doesn't have any abstract classes. Is it the case that this problem is not a good example of abstract classes?

I think, therefore I am. I think? - "George Carlin"
My Website: Indie Game Programming

My Twitter: https://twitter.com/indieprogram

My Book: http://amzn.com/1305076532

Quote:Original post by EvilWeebl
Hold on... could this be the answer?


This is what I had in mind at least when I tried to give you a hint. Whether it's the correct solution seems to be a matter of opinion and debate :)

I don't think there's any practical way to do double dispatch without having an interface somewhere that knows about all the implementing classes. You could apply the visitor pattern here, or simply make Hand an interface instead of an abstract class, but either way at some level you are tying them together.

Which kind of makes the whole thing pointless from a perspective of learning about abstract classes, but good for learning double dispatch. A good example of an abstract class is a class that provides some common functionality but is not useful by itself, something your hand class does not - for instance, an abstract widget in a user interface that provides positioning and resizing but not any actual content. Generally you will not really have many such classes since class hierarchies are a bit unwieldy and in most cases you will prefer composition (has-a) over inheritance (is-a).
Quote:Original post by Glass_Knife
Quote:Original post by CaptainJester
That will solve the problem sort of. But your real problem is that a parent class should never know what classes are sub classing it. Hand should not know or care that Rock, Paper and Scissors exist.


I agree with this, but what is the answer? The double dispatch doesn't have any abstract classes. Is it the case that this problem is not a good example of abstract classes?


I think that is the case. This is more a case for an enumerator.
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][LWJGL Tutorials for NeHe][LWJGL Wiki][jMonkey Engine]

This topic is closed to new replies.

Advertisement