/**
* Copyright (C) 2022 by Martin Robillard. See https://codesample.info/about.html
*/
package e2.chapter7;
/**
* Root class for all moves that require a reference
* to the GameModel. Method perform() fulfills the role
* of the Template Method in an application of the Template
* Method design pattern.
*/
public class AbstractMove implements Move {
protected final GameModel aModel;
AbstractMove(GameModel pModel) {
aModel = pModel;
}
@Override
public void perform() {
aModel.push(this);
;
log();
}
protected void execute();
private void log() {
System.out.println(getClass().getName());
}
}
This class must be declared abstract because its declaration includes an abstract method.
This class must be declared abstract because its declaration includes an abstract method.
Declaring the constructor of an abstract class to be protected is the logical choice, because it can only be called via subclasses.
Declaring the constructor of an abstract class to be protected is the logical choice, because it can only be called via subclasses.
This method is a . One of the steps in the algorithm
that it implements is a placeholder (namely the call to execute()
,
which is an abstract method.
This method is a . One of the steps in the algorithm
that it implements is a placeholder (namely the call to execute()
,
which is an abstract method.
The point of declaring a method abstract is so that we can explicitly refer to the abstraction that the method represents without needing to define it concretely in the abstract class. The implementation of the method then gets delegated to the subclasses.
The point of declaring a method abstract is so that we can explicitly refer to the abstraction that the method represents without needing to define it concretely in the abstract class. The implementation of the method then gets delegated to the subclasses.
The Template Method design pattern is a solution to implement a general class of algorithms, leaving some placeholders for the parts of the algorithm that vary from one context to another.
The pattern consists of implementing the common parts of the algorithm in a method (the template method) in an abstract class. This method will rely on abstract methods called primitives (the placeholders), which are implemented by subclasses.
Chapter 7, insight #14
Consider using the Template Method pattern in cases where an algorithm applies to all subclasses of a certain base class, except for some steps of the algorithm that must vary from subclass to subclass
The Template Method design pattern is a solution to implement a general class of algorithms, leaving some placeholders for the parts of the algorithm that vary from one context to another.
The pattern consists of implementing the common parts of the algorithm in a method (the template method) in an abstract class. This method will rely on abstract methods called primitives (the placeholders), which are implemented by subclasses.
Chapter 7, insight #14
Consider using the Template Method pattern in cases where an algorithm applies to all subclasses of a certain base class, except for some steps of the algorithm that must vary from subclass to subclass
Use of the final
keyword prevents any subclass from overridding
this method. Is thus ensures that any call to AbstractMove#execute
runs
this exact code.
Chapter 7, insight #15
If there is no scenario for overriding a method, consider declaring it final
. Similarly, if there is no specific reason for a class to be extensible using inheritance, consider declaring it final
.
Use of the final
keyword prevents any subclass from overridding
this method. Is thus ensures that any call to AbstractMove#execute
runs
this exact code.
Chapter 7, insight #15
If there is no scenario for overriding a method, consider declaring it final
. Similarly, if there is no specific reason for a class to be extensible using inheritance, consider declaring it final
.
AbstractMove
doesn't know what execute()
will do, but it knows how to
use the method as part of the perform()
implementation. This means that execute()
must be declared in this class (or a parent type) so that it can be called here.
But because the implementation isn't available yet, it must be abstract
.
Chapter 7, insight #13
Remember that abstract classes can define abstract methods, and that methods of the abstract class can call its own abstract methods. This way you can use abstract classes to define abstract implementations of algorithms
AbstractMove
doesn't know what execute()
will do, but it knows how to
use the method as part of the perform()
implementation. This means that execute()
must be declared in this class (or a parent type) so that it can be called here.
But because the implementation isn't available yet, it must be abstract
.
Chapter 7, insight #13
Remember that abstract classes can define abstract methods, and that methods of the abstract class can call its own abstract methods. This way you can use abstract classes to define abstract implementations of algorithms
Object
. The returned Class
object is the object that is locked by static synchronized
methods of the represented class.
Object
. The returned Class
object is the object that is locked by static synchronized
methods of the represented class.
The actual result type is Class<? extends |X|>
where |X|
is the erasure of the static type of the expression on which getClass
is called. For example, no cast is required in this code fragment:
Number n = 0;
Class<? extends Number> c = n.getClass();
Class
object that represents the runtime class of this object.
Class
object.
Class
object.
If this Class
object represents a class or interface, not an array class, then:
N + '/' + <suffix>
where N
is the binary name indicated by the class
file passed to Lookup::defineHiddenClass
, and <suffix>
is an unqualified name. If this Class
object represents an array class, then the result is a string consisting of one or more '[
' characters representing the depth of the array nesting, followed by the element type as encoded using the following table:
Element Type Encoding boolean
Z
byte
B
char
C
class or interface with binary name N L
N;
double
D
float
F
int
I
long
J
short
S
If this Class
object represents a primitive type or void
, then the result is a string with the same spelling as the Java language keyword which corresponds to the primitive type or void
.
Examples:
String.class.getName() returns "java.lang.String" Character.UnicodeBlock.class.getName() returns "java.lang.Character$UnicodeBlock" byte.class.getName() returns "byte" (new Object[3]).getClass().getName() returns "[Ljava.lang.Object;" (new int[3][4][5][6][7][8][9]).getClass().getName() returns "[[[[[[[I"
Class
object.
System
class contains several useful class fields and methods. It cannot be instantiated. Among the facilities provided by the System
class are standard input, standard output, and error output streams; access to externally defined properties and environment variables; a means of loading files and libraries; and a utility method for quickly copying a portion of an array.
System
class contains several useful class fields and methods. It cannot be instantiated. Among the facilities provided by the System
class are standard input, standard output, and error output streams; access to externally defined properties and environment variables; a means of loading files and libraries; and a utility method for quickly copying a portion of an array.
Console.charset()
if the Console
exists, stdout.encoding otherwise.
Console.charset()
if the Console
exists, stdout.encoding otherwise.
For simple stand-alone Java applications, a typical way to write a line of output data is:
System.out.println(data)
See the println
methods in class PrintStream
.
print(String)
and then println()
.
print(String)
and then println()
.
x
- The String
to be printed.