refactoring classes lesson six: classes. refactoring classes class decomposition is difficult....

Post on 17-Jan-2016

237 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

RefactoringClasses

Lesson Six: Classes

RefactoringClasses

Class Decomposition is difficult. Several Techniques exist: Behavioral Driven Design[Kowal] Data Driven Design[Mellor] State Driven Design[Schlaer] Responsibility Driven Design[Wirths-Brock] Discovery Driven Design [Norththrop] Framework Driven Design etc.

RefactoringClasses

Learning objective – have “good” classes which are reusable and easily maintained.

RefactoringClasses

We will use an approach which depends on clustering of methods, variables, and constants reside defined by McFadden. It is a data driven approach.

RefactoringClasses

Kind TypeVariables and Constants METHODS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

init

de

stro

y

dra

wG

rid

dra

wIm

ag

es

squ

are

Occ

up

ied

pa

int

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

use

Re

lea

sed

const int NINE-SHIFTING-BITSconst int ENDINGSTATE r r rconst int LOSE r r rconst int CONTINUE r r rconst int STALEMATE r r rconst int WIN r r rconst int NUMBER_OF_COLUMNS r r rconst int NUMBER_OF_ROWS r r rconst int FIRST_CELL r r rconst int LAST_CELL r r r

?? ??

SOME RED FLAGSSOME CLUSTERS

CONSTANTS

RefactoringClasses

VARIABLES

Kind Type Variables and Constants METHODS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

init

de

stro

y

dra

wG

rid

dra

wIm

ag

es

squ

are

Occ

up

ied

pa

int

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

use

Re

lea

sed

var int computerStatus p p p p p g s s s,g gvar int userStatus p p p p p p g s p s,gvar boolean computerFirst g svar Image computerImage s gvar Image userImage s gvar arrayint winningState[] u r r r

?? OK ??

RefactoringClasses

METHODS

Kind Type Variables, Constants, Methods METHODS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

init

de

stro

y

dra

wG

rid

dra

wIm

ag

es

squ

are

Occ

up

ied

pa

int

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

use

Re

lea

sed

ge

tUse

rMo

veS

tatu

s

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r rmethod void initmethod void destroymethod void drawGrid rmethod void drawImages rmethod boolean squareOccupied rmethod void paintmethod void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r rmethod void moveComputer rmethod void mouseReleased

RefactoringClasses

It is clear we need a GUI class that is separate from the domain of the game. This is a standard factorization and part of an architectural pattern called MVC (model view controller). We should have done this already in the previous lecture.

So I copy my class into a class called Domain and extract out from the TTT class all but the GUI related statements.

RefactoringClasses

public class TTTV61 extends Applet implements MouseListener {

// CONSTANTS static final int NUMBER_OF_COLUMNS = 3; static final int NUMBER_OF_ROWS = 3; // VARIABLES private Domain myDomain; // THIS IS ADDED private Image userImage; // user image private Image computerImage; // computer image

These variables belong with the GUI class(es).

RefactoringClasses

// GETS AND SETS public Image getUserImage (){return userImage;} public Image getComputerImage () { return computerImage;} public void setUserImage (Image userImage) { this.userImage = userImage;} public void setComputerImage (Image computerImage) { this.computerImage = computerImage; }

These methods also belong with the GUI class(es).

RefactoringClasses

//METHODS

public void init() { // initialize applet, load images, add listener setComputerImage(getImage(getCodeBase(), "oimage.gif")); setUserImage(getImage(getCodeBase(), "ximage.gif")); addMouseListener(this); myDomain = new Domain (); // ADDED } // end init

public void destroy() { removeMouseListener(this); } // end destroy

This method belongs to the commanding GUI class.

RefactoringClasses

public void drawGrid(Graphics g, Dimension d, int xoff, int yoff){ g.drawLine(xoff, 0, xoff, d.height); // draw first horizontal line g.drawLine(2*xoff, 0, 2*xoff, d.height); // draw second horizontal line g.drawLine(0, yoff, d.width, yoff); // draw first verticle line g.drawLine(0, 2*yoff, d.width, 2*yoff); // draw second verticle line } // end drawGrid

This method also belongs with the GUI class(es).

RefactoringClasses

public void drawImages(Graphics g, Dimension d, int xoff, int yoff){ int i = 0; for (int row = 0 ; row < NUMBER_OF_ROWS ; row++) { // draw computer and user images

for (int col = 0 ; col < NUMBER_OF_COLUMNS ; col++, i++) { int cs = myDomain.getComputerStatus();// THESE STATEMENTS CHANGED and TWO new methods in mydomain if (myDomain.computerOccupiesSquare (i)) {

g.drawImage(getComputerImage(), col*xoff + 1, row*yoff + 1, this); } else if (myDomain.userOccupiesSquare ( i)) {

g.drawImage(getUserImage(), col*xoff + 1, row*yoff + 1, this); } // end if }// end for

} // end for } // end draw Images

Again this method belong with the GUI class(es).

RefactoringClasses

public void paint(Graphics g) { // paint the screen

Dimension d = getSize(); g.setColor(Color.black);

int xoff = d.width / NUMBER_OF_ROWS; // compute x offsets int yoff = d.height / NUMBER_OF_COLUMNS; // compute y offsets

drawGrid (g, d, xoff, yoff); drawImages (g, d, xoff, yoff); } // end paint

This method belongs to the commanding GUI class.

RefactoringClasses

public void mouseReleased(MouseEvent e) { // user clicked applet int x = e.getX(); // get mouse x location int y = e.getY(); // get mouse y location Dimension d = getSize(); int col = (x * NUMBER_OF_COLUMNS) / d.width; // determine the column int row = (y * NUMBER_OF_ROWS) / d.height; // determine the row

if (gameOver (gameStatus(getComputerStatus(), getUserStatus()))) { resetGame(); repaint(); return; } // end if

Here there are methods and statements that are domain in nature.

For example the gameOver has to do with the domain of the game not the GUI. We need to extract out some of these methods from the GUI..

RefactoringClasses

int canidateMove = col + row * 3; if (legalUserMove(getComputerStatus(), getUserStatus(), canidateMove)) { repaint(); int status = getUserMoveStatus (canidateMove);

if (status == CONTINUE) { if (legalComputerMove(getComputerStatus(), getUserStatus())) { repaint(); moveComputer(getUserStatus());

} else { play(getCodeBase(), "audio/beep.au"); } // end else

} else { postGameStatus (status); } // end else } else { // not legal user move play(getCodeBase(), "audio/beep.au"); }// end else

} // end mouseReleased

All of these statements are domain in nature.

They need to be extracted in a method so they can be extracted to another class – The domain class.

RefactoringClasses

public void mouseReleased(MouseEvent e) { // user clicked applet int x = e.getX(); // get mouse x location int y = e.getY(); // get mouse y location Dimension d = getSize(); int col = (x * NUMBER_OF_COLUMNS) / d.width; // determine the column int row = (y * NUMBER_OF_ROWS) / d.height; // determine the row

// THIS CODE ADDED WITH ALL THE DOMAIN STATEMENTS EXTRACTED// NOTE: the this is passed to allow for repainting by the non applet myDomain.playGame(row,col, this); } // end mouseReleased

THUS, we extract the previous code into ONE method called playGame. Now mouseRelease is now only doing things associated with the GUI and calling a method for domain activity. No domain statements are included in the GUI, only calls to the DOMAIN class(es).

RefactoringClasses

public class TTTV61 extends Applet implements MouseListener { // CONSTANTS static final int NUMBER_OF_COLUMNS = 3; static final int NUMBER_OF_ROWS = 3; // VARIABLES private Domain myDomain; private Image userImage; // user image private Image computerImage; // computer image

// GETS AND SETS public Image getUserImage (){return userImage;} public Image getComputerImage () { return computerImage;} public void setUserImage (Image userImage) { this.userImage = userImage;} public void setComputerImage (Image computerImage) { this.computerImage = computerImage; }

Here is the GUI class after all methods have been extracted that belong to the DOMAIN.

I HAVE TO ADD a variable for the domain class DOMAIN.

RefactoringClasses

//METHODS

public void init() { // initialize applet, load images, add listener setComputerImage(getImage(getCodeBase(), "oimage.gif")); setUserImage(getImage(getCodeBase(), "ximage.gif")); addMouseListener(this); myDomain = new Domain (); } // end init

public void destroy() { removeMouseListener(this); } // end destroy

WE keep the init and destroy methods in the GUI.

Here I make an instance of the new class called DOMAIN.

RefactoringClasses

public void drawGrid(Graphics g, Dimension d, int xoff, int yoff){ g.drawLine(xoff, 0, xoff, d.height); // draw first horizontal line g.drawLine(2*xoff, 0, 2*xoff, d.height); // draw second horizontal line g.drawLine(0, yoff, d.width, yoff); // draw first verticle line g.drawLine(0, 2*yoff, d.width, 2*yoff); // draw second verticle line } // end drawGrid

WE keep the drawGrid method in the GUI.

RefactoringClasses

public void drawImages(Graphics g, Dimension d, int xoff, int yoff){ int i = 0; // draw computer and user images for (int row = 0 ; row < NUMBER_OF_ROWS ; row++) {

for (int col = 0 ; col < NUMBER_OF_COLUMNS ; col++, i++) { int cs = myDomain.getComputerStatus(); if (myDomain.computerOccupiesSquare(i)) {

g.drawImage(getComputerImage(), col*xoff + 1, row*yoff + 1, this); } else if (myDomain.userOccupiesSquare(i)) {

g.drawImage(getUserImage(), col*xoff + 1, row*yoff + 1, this); } // end if }// end for

} // end for } // end draw Images

WE keep the drawImages method in the GUI.

Note the references to the DOMAIN class.

RefactoringClasses

public void paint(Graphics g) { // paint the screen

Dimension d = getSize(); g.setColor(Color.black);

int xoff = d.width / NUMBER_OF_ROWS; // compute x offsets int yoff = d.height / NUMBER_OF_COLUMNS; // compute y offsets

drawGrid (g, d, xoff, yoff); drawImages (g, d, xoff, yoff); } // end paint

WE keep the paint method in the GUI and it uses other GUI methods.

RefactoringClasses

public void mouseReleased(MouseEvent e) { // user clicked applet

int x = e.getX(); // get mouse x location int y = e.getY(); // get mouse y location

Dimension d = getSize();

int col = (x * NUMBER_OF_COLUMNS) / d.width; // determine the column int row = (y * NUMBER_OF_ROWS) / d.height; // determine the row

myDomain.playGame(row,col, this);

} // end mouseReleased

WE keep the mouseReleased method in the GUI.

It calls the playGame method in the DOMAIN class.

RefactoringClasses

public void mousePressed(MouseEvent e) { }

public void mouseClicked(MouseEvent e) { }

public void mouseEntered(MouseEvent e) { }

public void mouseExited(MouseEvent e) { }

public String getAppletInfo() {return "TicTacToe by Arthur van Hoff"; }} // end TTT

WE keep the these methods in the GUI.

RefactoringClasses

Now we need to look at the domain class because it currently has a hodge podge of statements and methods that may need more class refactoring.

Next few slides show the resulting DOMAIN class.

RefactoringClasses

import java.applet.*;

public class Domain { // CONSTANTS static final int NINE_SHIFTING_BITS = 9; static final int ENDINGSTATE = (1 << NINE_SHIFTING_BITS) - 1; static final int LOSE = 2; // status for user wins static final int CONTINUE = 0; // OLD OK status for game continues static final int STALEMATE = 3; // status for a tie static final int WIN = 1; // status for computer wins static final int FIRST_CELL = 0; // first cell at row 1 col 1 static final int LAST_CELL = 8; // last cell at row 3, col 3

RefactoringClasses

// VARIABLES

private int computerStatus; ; // computer bitmask denotes squares occupied private boolean computerFirst = true; // who goes first next game private int userStatus; // user bitmask denotes user squares occupied private static boolean winningState[] = new boolean[1 << 9]; // winning states

private Applet myApplet;

WE need to declare the myApplet here so we can call repaint when we need to in the movment of the TTT tokens.

RefactoringClasses

private static void setWinningState(int winState) { // mark squares as true win for (int i = 0 ; i < ENDINGSTATE ; i++) { if ((i & winState) == winState) {winningState[i] = true; } } // end for } // end isWon static { // initialize winning squares by shifting a one n bits setWinningState((1 << 0) | (1 << 1) | (1 << 2)); // row one 000 000 111 setWinningState((1 << 3) | (1 << 4) | (1 << 5)); // row two 000 111 000 setWinningState((1 << 6) | (1 << 7) | (1 << 8)); // row three 111 000 000 setWinningState((1 << 0) | (1 << 3) | (1 << 6)); // col one 100 100 100 setWinningState((1 << 1) | (1 << 4) | (1 << 7)); // col two 010 010 010 setWinningState((1 << 2) | (1 << 5) | (1 << 8)); // col three 001 001 001 setWinningState((1 << 0) | (1 << 4) | (1 << 8)); // dia right 100 010 001 setWinningState((1 << 2) | (1 << 4) | (1 << 6)); // dia left 001 010 100 } // end static

RefactoringClasses

public int getComputerStatus () { return computerStatus; } public boolean getComputerFirst () { return computerFirst; } public int getUserStatus () { return userStatus; } public void setComputerStatus (int computerStatus) { this.computerStatus = computerStatus; } public void setComputerFirst (boolean computerFirst) { this.computerFirst = computerFirst; } public void setUserStatus (int userStatus) { this.userStatus = userStatus; }

public void setMyApplet (Applet myApplet) { this.myApplet = myApplet;}

WE need a setMyApplet method to set the class variable for use in many methods. Remember it was a parameter called by playGame in the GUI class.

RefactoringClasses

//METHODSpublic void Domain () { } NEW CONSTRUCTOR

public void playGame(int row, int col,Applet myApplet) { setMyApplet (myApplet); if (gameOver (gameStatus(getComputerStatus(), getUserStatus()))) { resetGame(); myApplet.repaint(); // NOTE REFERENCE return; } // end if

WE NEED a CONSTRUCTOR method.

Note the reference to myApplet.repaint which allows you to redraw the images after a move has been made.

RefactoringClasses

// playGame CONTINUED int canidateMove = col + row * 3;

if (legalUserMove(getComputerStatus(), getUserStatus(), canidateMove)) { makeMoves( canidateMove);

} else { // not legal user move myApplet.play(myApplet.getCodeBase(), "audio/beep.au"); }// end else } // end playGame

RefactoringClasses

public void continuePlaying ( ) { if (legalComputerMove(getComputerStatus(), getUserStatus())) { myApplet.repaint(); moveComputer(getUserStatus()); postGameStatus(gameStatus(getComputerStatus(), getUserStatus())); } else { myApplet.play(myApplet.getCodeBase(), "audio/beep.au"); } // end else } // end continueGame

public void makeMoves (int canidateMove) { myApplet.repaint(); moveUser(canidateMove); int status = gameStatus(getComputerStatus(), getUserStatus()); if (status == CONTINUE) { continuePlaying(); } else { postGameStatus (status); } // end else } // end makeMoves

NEW METHODS as a further refactoring to make methods functional.

RefactoringClasses

public boolean cellEmpty(int computerStatus,int potentialComputerMove,int userStatus) { return ((computerStatus & (1 << potentialComputerMove)) == 0) && ((userStatus & (1 << potentialComputerMove)) == 0); } // end cellEmpty

public boolean userWins (int potentialComputerStatus, int userStatus) { for (int userMove = FIRST_CELL ; userMove <= LAST_CELL ; userMove++) { // for square = 0 to < 9 if (cellEmpty (potentialComputerStatus, userMove, userStatus)) { int potentialUserStatus = userStatus | (1 << userMove);

if (winningState[potentialUserStatus]) { // user wins, take another return true; } // end if won

} // end if cellEmpty } // end for return false; } // end checkIfUserWon

RefactoringClasses

public int bestMove(int computerStatus, int userStatus) { // compute best move int mostStrategicMove[] = {4,0,2,6,8,1,3,5,7};// square order of importance int bestMoveNotFound = -1; int bestmove = bestMoveNotFound;

RefactoringClasses

loop: for (int i = FIRST_CELL ; i <= LAST_CELL ; i++) { int potentialComputerMove = mostStrategicMove[i]; if (cellEmpty (computerStatus, potentialComputerMove, userStatus)) { int potentialComputerStatus = computerStatus | (1 << potentialComputerMove); if (winningState[potentialComputerStatus]) { // computer wins, take it!

return potentialComputerMove;} /// end if (not user taken ) && ( not computer taken )

if (userWins (potentialComputerStatus, userStatus)) { continue loop;} if (bestmove == bestMoveNotFound) { // neither can win, move will do bestmove = potentialComputerMove; } // end if } // end if && } // end for

RefactoringClasses

if (bestmove != bestMoveNotFound) { // if no move found return the best one return bestmove;

} // end if bestmove

// no great move, try first one open for (int anyMove = FIRST_CELL ; anyMove <= LAST_CELL ; anyMove++) { int firstAvailableComputerMove = mostStrategicMove[anyMove]; if (cellEmpty (computerStatus, firstAvailableComputerMove, userStatus)) { return firstAvailableComputerMove; } // end if && } // end for return bestMoveNotFound; // return no more moves } // end best move

RefactoringClasses

public boolean legalUserMove(int computerStatus, int userStatus, int canidateMove) { if ((canidateMove < FIRST_CELL) || (canidateMove > LAST_CELL)) { return false; } // end if if (squareOccupied (canidateMove, userStatus | computerStatus)) {

return false; } // end if return true; } // end legalUserMove

public boolean legalComputerMove(int computerStatus, int userStatus) { if ((userStatus | computerStatus) == ENDINGSTATE) { return false; } // end if return true;} // end legalComputerMove

RefactoringClasses

Public int gameStatus(int computerStatus, int userStatus ) { // if (win, loose, tie) if (winningState [computerStatus]) { return WIN; } // end if if (winningState [userStatus]) { return LOSE; } // end if if ((userStatus | computerStatus) == ENDINGSTATE) { return STALEMATE; } // end if return CONTINUE; } // end gameStatus public boolean squareOccupied (int i, int playerStatus) { return (( playerStatus & (1 << i)) != 0); } // end squareOccupied

RefactoringClasses

public void playComputerIfFirst ( ) { if (getComputerFirst()) {setComputerStatus ( 1 << (int)(Math.random() * 9)); }} // end playcomputerIfFirst

public void resetGame () { setComputerStatus(0); setUserStatus(0); playComputerIfFirst (); setComputerFirst (!getComputerFirst()); } // end resetGame

RefactoringClasses

public boolean gameOver(int status) { // check if over after computer move switch (status) {

case WIN:case LOSE:case STALEMATE:

return true; default:

return false; } // end switch } // end gameOver

RefactoringClasses

public void postGameStatus (int status) { switch (status) { case WIN: System.out.println ("I win ");

break; case LOSE: System.out.println ("You win "); break; case STALEMATE:

System.out.println ("No Winner "); break; default:

} // end switch } // end checkGameStatus

RefactoringClasses

public void moveComputer( int userStatus) { setComputerStatus (getComputerStatus() | 1 << bestMove(getComputerStatus(), userStatus)); } // end computerMove public void moveUser (int canidateMove) { setUserStatus (getUserStatus ( ) | 1 << canidateMove); } // end moveUser

RefactoringClasses

For EACH variable 1. Find the set method(s) for that VARIABLE. 2. Determine the SET of methods that use the set methods.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

bes

tMo

ve

leg

alU

serM

ove

leg

alC

om

pute

rMo

ve

gam

eS

tatu

s

pla

yCo

mpu

terI

fFirs

t

rese

tGa

me

gam

eO

ver

pos

tGa

meS

tatu

s

mo

veC

om

pu

ter

get

Use

rMo

veS

tatu

s

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

upie

d

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod int getUserMoveStatus rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean spaceOccupied r rmethod boolean continuePlayingmethod void constructor

var int computerStatus p p p p p s s s,g g g pi gvar int userStatus p p p p p p s p g,s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r rvar Applet myApplet p

RefactoringClasses

3. For each method in the SET (set method callers)4. Determine the variables referenced and set by each

method.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

bes

tMo

ve

leg

alU

serM

ove

leg

alC

om

pute

rMo

ve

gam

eS

tatu

s

pla

yCo

mpu

terI

fFirs

t

rese

tGa

me

gam

eO

ver

pos

tGa

meS

tatu

s

mo

veC

om

pu

ter

get

Use

rMo

veS

tatu

s

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

upie

d

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod int getUserMoveStatus rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean spaceOccupied r rmethod boolean continuePlayingmethod void constructor

var int computerStatus p p p p p s s s,g g g pi gvar int userStatus p p p p p p s p g,s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r rvar Applet myApplet p

RefactoringClasses

These X references are STRONG clusters. THUS, the STRONG Canidates for clustering are playComputerIfFirst and resetGame and moveComputer

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

bes

tMo

ve

leg

alU

serM

ove

leg

alC

om

pute

rMo

ve

gam

eS

tatu

s

pla

yCo

mpu

terI

fFirs

t

rese

tGa

me

gam

eO

ver

pos

tGa

meS

tatu

s

mo

veC

om

pu

ter

get

Use

rMo

veS

tatu

s

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

upie

d

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod int getUserMoveStatus rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean spaceOccupied r rmethod boolean continuePlayingmethod void constructor

var int computerStatus p p p p p s s s,g g g pi gvar int userStatus p p p p p p s p g,s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r rvar Applet myApplet p

RefactoringClasses

Now we look at the LOOSE clusterings. THUS the WEAK canidates for clustering are playGame and continuePlaying and bestMove.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

bes

tMo

ve

leg

alU

serM

ove

leg

alC

om

pute

rMo

ve

gam

eS

tatu

s

pla

yCo

mpu

terI

fFirs

t

rese

tGa

me

gam

eO

ver

pos

tGa

meS

tatu

s

mo

veC

om

pu

ter

get

Use

rMo

veS

tatu

s

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

upie

d

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod int getUserMoveStatus rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean spaceOccupied r rmethod boolean continuePlayingmethod void constructor

var int computerStatus p p p p p s s s,g g g pi gvar int userStatus p p p p p p s p g,s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r rvar Applet myApplet p

RefactoringClasses

We can determine ALL the STRONG methods, labeled in red.

computerStatus

userStatus

computerFirst

winningStatus

resetGame

playComputerIfFirst

moveComputer

resetGame

moveUser

resetGame

setWinningState

RefactoringClasses

Note that the resetGame method is Strong in with several class variables, so I will place it in the undecided box.

computerStatus

userStatus

computerFirst

winningStatus

resetGame

playComputerIfFirst

moveComputer

resetGame

moveUser

resetGame

setWinningState

Undecided

resetGame-S

RefactoringClasses

We can see that the two strong methods of computerStatus. The method playComputer references nonone but does a get on computerFirst. The method moveComputer references bestMove and does a get to computerStatus and userStatus .

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

RefactoringClasses

Now we look at what these methods are referenced by. The Strong method playComputeIfFirst is referenced by resetGame. The Strong method moveComputer is referenced by continueplaying.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

RefactoringClasses

computerStatus

userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-ScomputerFirst

set

getref

The STRONG method playComputerFirst references noone. It is referenced by resetGame and gets the class variable computerFirst. We can see how these items begin to cluster together to form natural classes.

We show these sets, gets, references and parameters using a Rosetta-like map. A legend below shows how to read the map.

params

playGame

continuePlaying

RefactoringClasses

computerStatus

userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-ScomputerFirst

set

getref

bestMove

params

continuePlaying

Now we look at the next STRONG method moveComputer.

The method moveComputer references bestMove, gets computerStatus, and is referenced by continuePlaying.

playGame

RefactoringClasses

computerStatus

userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-ScomputerFirst

set

getref

bestMove

params

continuePlaying

Now we look at the next STRONG method moveComputer.

The method moveComputer references bestMove, gets computerStatus, and is referenced by continuePlaying.

playGame

RefactoringClasses

computerStatus

userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-ScomputerFirst

set

getref

The STRONG method playComputerFirst references noone. It is referenced by resetGame and gets the class variable computerFirst. We can see how these items begin to cluster together to form natural classes.

We show these sets, gets, references and parameters using a Rosetta-like map. A legend below shows how to read the map.

params

playGame

continuePlaying

RefactoringClasses

computerStatus

userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-ScomputerFirst

set

getref

bestMove

params

continuePlaying

Now we look at the next STRONG method moveComputer.

The method moveComputer references bestMove, gets computerStatus, and is referenced by continuePlaying.

playGame

RefactoringClasses

We then look at the Strong methods for userStatus and continue to trace its related references.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

RefactoringClasses

computerStatus

userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-ScomputerFirst

set

getref

bestMove

params

Now we look at the next STRONG method moveUser.

The method moveUser references nothing but is referenced by makeMoves. The methods continuePlaying and playGame perform gets on userStatus.

makeMoves

continuePlaying

playGame

RefactoringClasses

The third variable computerFirst has its only strong method resetGame in undecided. It does have a get from playComputerIfFirst but that has already been noted on the graph.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

RefactoringClasses

The last variable winninStatus is updated (set) by the strong method setWinningStatus and setWinningStatus references nothing.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

RefactoringClasses

computerStatus

userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-ScomputerFirst

set

getref

bestMove

params

STRONG methods for computerFirst and for winningStatus

The method setWinningStatus references nothing. But winningStatus does havereferences (gets) from userWins, bestMove, and gameStatus. We will do params later.

makeMoves

continuePlaying

playGame

userWins

gameStatus

RefactoringClasses

setgetrefparams

We will begin by defining variable clusters first.

It is clear that variable clusters computerStatus and userStatus are tightly coupled.

The winningStatus cluster could be moved out with or without bestMove.

The computerFirst cluster could be moved out or included with the computerStatus cluster.

computerStatus

userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-ScomputerFirst

bestMove

makeMoves

continuePlaying

playGame

userWins

gameStatus

RefactoringClasses set

getrefparams

Now we need to group and expand this graph to see how the others cluster.

We begin by defining computerStatus/userStatus as one cluster and expand it out.

At this point we have the computerStatus/userStatus cluster with the methods moveUser and moveComputer as Strong and weak methods of continuePlaying, playGame, makeMoves, and bestMove.

computerStatus/userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-ScomputerFirst

bestMove makeMoves

continuePlaying

playGame

userWins

gameStatus

RefactoringClasses

Now we need to trace backwards from the weak methods to see their references. We first do it for the new cluster computerStatus/userStatus. Those include continuePlaying, playGame, and makeMoves.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

RefactoringClasses

setgetrefparams

This tightens this clustering. The extended method makeMoves calls two of the weaker methods continuePlaying and playGame and also performs gets to both of the class variables. The extended methods are labeled in blue.

The methods continuePlaying, playGame and makeMoves are now classified as strong with the references to one another and the references to the class variables.

computerStatus/userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-S computerFirst

bestMove

makeMoves

continuePlaying

playGame

userWins

gameStatus

gameOver

postGameStatus

legalUserMove

legalComputerMove

RefactoringClasses

Before we decide to bring the strong methods into the cluster, we look at the methods that are also reference these strong methods. Since no more methods are referenced then we try them in the cluster.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

RefactoringClasses

setgetrefparams

After we bring in the strong methods into the computerStatus/userStatus cluster, we can then look at the extended methods. This is not a one shot process. It make several attempts at clustering until you find the BEST solution since a perfect solution may not be possible. I usually save each version of clustering to allow regression.

The extended methods are legalComputerMove, legalUserMove, gameOver and postGameStatus

computerStatus/userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-S computerFirst

bestMove

makeMoves

continuePlaying

playGame

userWins

gameStatus

gameOver

postGameStatus

legalUserMove

legalComputerMove

RefactoringClasses

We look at these methods we note while the use the class variables of the current cluster as parameters or indirect parameters, they call one other method squareOccupied. Then we look at who references them and see those methods are already in the cluster.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

RefactoringClasses

setgetrefparams

However, we show the linkages. These are the leaves of the linkages and they are targets for clustering with other clusters. It is difficult to know when you should stop and liik at the other potential clusterings. Possible scenarios are to do all the potential clusters and their weak methods then look at what might can be enclosed in a cluster.

We will stop here and look at what methods remain

computerStatus/userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-S computerFirst

bestMove

makeMoves

continuePlaying

playGame

userWins

gameStatus

gameOver

postGameStatus

legalUserMove

legalComputerMove

squareOccupied

RefactoringClasses

Now lets look at the methods that are included in the first cluster.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

RefactoringClasses

Now lets look at the methods that are included in the first cluster.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

RefactoringClasses

setgetrefparams

Houston, we have clustering of two classes. The computerStatus/userStatus cluster now named PlayGame, will contain all the methods it takes to actually play the game. Another cluster named GameStrategy, will contain all the methods, regardless how simple, we are using to help the computer to win the game.

It only makes sense to put resetGame, and playComputerIfFirst in the Game class.

computerStatus/userStatus

winningStatus

playComputerIfFirst

moveComputer

moveUser

setWinningState

Undecided

resetGame-S

computerFirst

bestMove

makeMoves

continuePlaying

playGame

userWins

gameStatus

gameOver

postGameStatus

legalUserMove

legalComputerMove

squareOccupied

cellEmpty

userWins

RefactoringClasses

Now lets look at the methods that are included in the first cluster.

Kind Type Variables, Constants, Methods DOMAIN CLASS

setW

inn

ing

Sta

te

cellE

mp

ty

use

rWin

s

be

stM

ove

leg

alU

serM

ove

leg

alC

om

pu

terM

ove

ga

me

Sta

tus

pla

yCo

mp

ute

rIfF

irst

rese

tGa

me

ga

me

Ove

r

po

stG

am

eS

tatu

s

mo

veC

om

pu

ter

mo

veU

ser

ma

keM

ove

s

pla

yGa

me

squ

are

Occ

up

ied

con

tinu

eP

layi

ng

method void setWinningStatemethod boolean cellEmpty r rmethod boolean userWins rmethod int bestMove rmethod boolean legalUserMove rmethod boolean legalComputerMove rmethod int gameStatus r r

method void playComputerIffirst rmethod void resetGame rmethod boolean gameOver rmethod void postGameStatus r r

method void moveComputer rmethod void moveUser rmethod void makeMoves rmethod void playGamemethod boolean squareOccupied rmethod boolean continuePlaying rmethod void constructor

var int computerStatus p p p p p s s pi pi s,g g pi gvar int userStatus p p p p p p s pi pi p s g pi gvar boolean computerFirst g s,gvar arrayint winningState[] u r r r

`

top related