Versjon 7 av sjakk med JavaFX og FXML
Denne versjonen innfører en klasse for hver brikketype, som kjenner reglene for flytting av brikker av den typen,
i stedet for at alle reglene ligger i Chess
-klassen. Dette gjør konstruksjonen ryddigere og potensielt mer utvidbart
(med nye brikketyper, selv om det ikke er så aktuelt for akkurat sjakk).
Polymorfi og arv
Sentralt for denne typen løsning er at alle brikker kan det samme, nemlig å si om et gitt (forsøk på) flytt er lov, men har ulike regler (basert på brikketype) for å sjekke det. Dette kalles polymorfi, som kan oversettes til noe sånt som har flere former.
Teknikken er som følger:
-
De felles egenskapene eller ferdighetene deklareres i en egen klasse. Vi kaller klassen
PieceKind
, og de felles ferdighetene er metodenegetSymbol
ogcheckMove(…)
. -
Siden det ikke finnes noen generell implementasjon av
checkMove
-metoden, så deklareres metoden som abstrakt (abstract
), og da må klassen også deklareres som det. Dette betyr at vi ikke kan instansierePieceKind
direkte, siden implementasjonen avcheckMove
mangler. -
For hver brikketype lager vi en subklasse som arver fra
PieceKind
(extends PieceKind
) og implementerercheckMove
iht. reglene for den brikketypen. Siden en slik klasse vil ha implementert alle nødvendige metoder, så kan den være konkret/instansierbar, i motsetning til abstrakt. -
Når en annen klasse kaller
checkMove
på en (instans av en) spesifikk brikketype, altså instans av en subklasse avPieceKind
, så kjøres den tilsvarende brikkespesifikkecheckMove
-metoden.
package javafx.chess.v7;
import java.util.Collection;
import java.util.List;
public abstract class PieceKind {
public char getSymbol() {
String s = toString();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (Character.isUpperCase(c)) {
return c;
}
}
throw new UnsupportedOperationException("getSymbol does not work with the toString method");
}
public abstract void checkMove(Piece piece, char toLine, int toRow, Chess chess);
protected void checkNoPieceInBetween(Piece piece, char toLine, int toRow, Chess chess) {
if (chess.isPieceBetween(piece, toLine, toRow, chess.findPieceAt(toLine, toRow))) {
throw new IllegalArgumentException("A " + this + " cannot jump over other pieces");
}
}
private static Collection<PieceKind> ALL_KINDS = List.of(
new KingKind(),
new BishopKind(),
new QueenKind(),
new RookKind(),
new KnightKind(),
new PawnKind()
);
public static PieceKind of(char kind) {
for (PieceKind pieceKind : ALL_KINDS) {
if (pieceKind.getSymbol() == kind) {
return pieceKind;
}
}
return null;
}
}
Endringer i Piece
Piece
sin kind
-variabel bytter type fra char
til PieceKind
.