Reference: Object Oriented Design and Programming (Horstmann) 2. Java OOP Reference: Object Oriented Design and Programming (Horstmann)
Review + Vocabulary A class is a blueprint for a new type You define how all instances will be structured An object is an instance (variable) of that type Composed of attributes (variables) and methods (functions) Java allows two types of each: instance variables / methods: must be accessed through an instance class (static) variables / methods: can be accessed through the class itself
Simple example package chess_pieces; public class Pawn { protected boolean mIsWhite; // INSTANCE VARIABLES protected int mRow, mCol; // A special CONSTRUCTOR method (called when allocating with new) // Note: no return value! public Pawn(int r, int c, boolean white) mIsWhite = white; mRow = r; mCol = c; } // an example of a GETTER (and a METHOD) public int get_row() return mRow; // an example of a SETTER (returns true if this is a valid move) public boolean make_move(int new_row, int new_col) if (...) // We'd need actual code here... mRow = new_row; mCol = new_col; package oop_example; import chess_pieces.*; public class Oop_example { public static void main(String[] args) Pawn p1 = new Pawn(4, 6, true); Pawn p2 = new Pawn(2, 3, false); System.out.println(p1.getRow()); System.out.println(p2.getRow()); }
What’s the deal with m…? Just my code convention: put m in front of all class members. Attributes are “clumped” in code-completion Avoids duplicate names… “this” A special keyword Always holds a reference to the instance invoking this method. A way to dis-ambiguate. Always available (except in static methods…) public class Foo { int x; public Foo(int x) x = x; // Pointless! this.x = x; }
Access Modifiers The public / private / protected / (nothing) affect who can access that thing. 4 contexts (increasingly remote): in the class: we’re in the class, accessing something in that class. package: we’re in a different file, but in the same package as the class member we’re accessing subclass: we’re a sub-class (later in inheritance) of the class we’re trying whose member we’re accessing. world: completely separate from the class we’re accessing. https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
Suppose… …we’re now adding the other pieces (Rook, Queen, etc.) They’ll all be very similar exactly the same attributes very similar methods (although the makeMove would internally be different) We may want to store all pieces in the game in an array: @@@[] all_pieces = new @@@[32]; What’s @@@? In loosely-typed languages (e.g. Python, Ruby, Lua), we’d just make a list and throw these heterogenous types into it. Java is strongly-typed. It won’t allow this. Solution (in Java): interface classes
Java Interface (classes) A Java interface is similar to a class, but… Can’t contain attributes Methods are only stubs (no body) Used to describe common functionality between classes. Another class can implement that Interface. To Java, this new class is of the interface type (polymorphism) A “contract” – the new class must implement that method. When an implemented method is called, the JVM determines (at run time) which method to actually call. A new class can implement any number of interfaces. package chess; public interface Piece { public int get_row(); public boolean make_move(int new_row, int new_col); } public class Pawn implements Piece { protected boolean mIsWhite; protected int mRow, mCol; // Constructor as before @Override public int get_row() { /* as before... */ } public boolean make_move(int new_row, int new_col) { /* as before... */ } } Piece[] all_pieces = new Piece[32]; all_pieces[0] = new Pawn(4, 3, true); all_pieces[1] = new Rook(0, 0, false); all_pieces[2] = new Queen(0, 4, false);
Is it perfect? Sometimes, but not always. In our example, all the new classes (Pawn, Rook, etc.) would have a lot of duplicate code Same attributes Many of the methods are the same (makeMove is the only one that’s really unique). Usually duplicated code is a sign of poor software design. It takes effort (programmers are lazy!) If we find a bug, we must remember to copy-paste it. More code = Harder to understand The fix here: “true” inheritance (extends)
extends inheritance Basic idea Modifying our example: Define a base-class contains all common code (attributes, methods [with bodies]) When defining a new (derived) class, extend from the base class. A class can only extend from one other class (A Java-only limitation) Modifying our example: Change Piece from an interface to a regular class Pull any common code to the Piece class Force the derived classes to implement new_move (abstract keyword) Change the way we create the new classes. The list of Pieces is unchanged!
Extends example package chess; public abstract class Piece { protected boolean mIsWhite; protected int mRow, mCol; public Piece(int r, int c, boolean white) mIsWhite = white; mRow = r; mCol = c; } public int get_row() return mRow; public abstract boolean make_move(int new_row, int new_col); package chess; public class Pawn extends Piece { public Pawn(int r, int c, boolean white) super(r, c, white); // Calls base-class ctor // Additional setup would go here… } @Override public boolean makeMove(int new_row, int new_col) //if (...) if (true) mRow = new_row; mCol = new_col; return true; return false;
Intro to Slick2d What is it? Cross-platform (Linux, OSX, Win) An example of an external dependency Also uses native libraries (written in C most likely) Windows = .dll OSX = .dylib Linux = .so “Linked” to the JVM at run-time Graphics, Animation, Input We'll use it for simple visualizations Good example of inheritance Has a few (mostly-easy) setup steps that are IDE / platform specific
Inheritance in Slick2d Main class overview You Create a class (Foo) that extends BasicGame (org.newdawn.slick.BasicGame) Override 3 main methods: init, update, and render Create (in main) an AppGameContainer (bob) and a Foo inst (hat) Attach hat to bob (by passing it to bob's constructor) Call Bob's start method – that will call the 3 methods of Hat at appropriate times.
Listener design pattern A very common design pattern Two classes Observer: wants to be notified when an event happens on the Observed Ovserved: Notifies the Observer(s) when the event happens Used by Slick’s mouse / keyboard handling [Discuss] public interface Observer { public void handleEvt(Event e); } public class RealListener implements Observer { // Other data / methods go here. public void handleEvt(Event e) // Put code to actually process the // event here. } public class Observed { // Other data / methods here protected Observer mListener; // Could be a list public void setListener(Observer o) { mListener = o; } public void removeListener() { mListener = null; } public void update() // Called by the main program? if (??? && mListener != null) mListener.handleEvt(new Event(…)); } Observed Obj = new Observed(…); … RealListener L = new RealListener(…); Obj.setListener(L); Obj.setListener(null);