Reputation: 475
Any idea how I can avoid these repeated class parameters?
abstract class XClass( var x: Int, var y: Int, var w: Int, var h: Int) {...}
abstract class MXClass( var xS: Int, var yS: Int, var wS: Int, var hS: Int)
extends XClass (xS, yS, wS, hS)
class PXClass( var xP: Int = 0, var yP: Int = 0, var wP: Int = 0, var hP: Int = 0)
extends MXClass (xP, yP, wP, hP)
def draw(g: Graphics2D) {
g fillRect (x, y, w, h)
}
then I have something like this in a GUI
:
g setColor black
val cc = new PXClass(200, 300, 10, 10)
cc.draw(g)
So I am giving those parameters as they are needed in the GUI
!
Thanks
Upvotes: 2
Views: 310
Reputation: 38247
According to what you said:
the XClass is a Piece class and MXClass is a MovablePiece then PXClass is RectanglePiece class. Then I need Piece class to extend by StationaryPiece, thus I am trying to have some movable and statinary pieces in a BoardPanel of different shapes. – Val 18 mins ago
Let's just start out by defining them one by one — let's not use any inheritance because it's not immediately obvious it's even needed; you can come back to inheritance (or some other type of polymorphism) when needed but trust me it's never actually needed:
sealed trait Shape
case object Rectangle extends Shape
case object Square extends Shape
case object Circle extends Shape
case class Dimensions(x: Int, y: Int, w: Int, h: Int)
case class Piece(shape: Shape, dim: Dimensions, isMovable: Boolean = true)
val squarePiece = Piece(Square, Dimensions(x = 100, y =. 200, w = 20, h = 20))
val circularPiece = Piece(Circular, Dimensions(x = 0, y = -100, w = 40, h = 40))
val immovableRectPiece = Piece(Rectangle, Dimensions(...), isMovable = false)
and then you can define a function to take any piece and draw it:
def draw(piece: Piece) = piece.shape match {
case Rectangle => ...
case Square => ...
case Circle => ...
}
...and methods for binary functions:
case class Piece(...) {
def collidesWith(other: Piece) = ...
def overlapsWith(other: Piece) = ...
}
then:
draw(immovablePiece)
if (piece1 collidesWith piece2) ...
if (piece1 overlapsWith piece2) ...
You're free to make draw
a method of Piece
as well, but it doesn't really matter — if you manage to avoid inheritance, all methods become equivalent to plain functions anyway.
There is no need to use inheritance (i.e. subtype polymorphism); it's always best to start out with mathematically purer concepts and avoid extends
altogether. If you consider the code I've demonstrated, you'll realise that it gives you a way to compose bits and pieces instead of providing monolithic types; it also allows you to convert one type of piece to another by providing an alternative value for an attribute — this is not possible with inheritance; it's not possible to change the type of an object once created.
val immovableCirclePiece = circularPiece.copy(isMovable = false)
Note that the Shape
inheritance tree starting with that sealed trait
is not the same as regular inheritance — what it does it defines an Algebraic Data Type, which in this case resembles quite closely what would be an enum
in Java.
Furthermore, you could try to extract the data that is relevant to drawing/rendering and put it all in a, say, Representation
class that holds both the Point
as well as a rendering function to draw specific shapes. Feel free to ask for clarification — there's a lot to say and I'm only trying to get you started with designing your programs in a more sophisticated manner :)
Upvotes: 5