codice legacy, usciamo dal pantano!
TRANSCRIPT
Codice Legacy,usciamo dal pantano!
Antonio Carpentieri (@acarpe)Stefano Leli (@sleli)
giovedì 30 giugno 2011
Regole
•Tempo a disposizione: 50 minuti
• Il codice va rifattorizzato per essere conforme ai principi S.O.L.I.D.
• I test possono essere modificati
giovedì 30 giugno 2011
S.O.L.I.D. Principles
giovedì 30 giugno 2011
giovedì 30 giugno 2011
Single Responsibility Principle
“There should never be more than one reason for a class to change”
giovedì 30 giugno 2011
giovedì 30 giugno 2011
Interface Segregation Principle
public interface MobileDevice{ void Call(string phoneNumber); void PlayAudio(Uri uri); void PlayVideo(Uri uri); void TakePicture(); void StartRecordingAudio(); void StopRecordingAudio(); void StartRecordingVideo(); void StopRecordingVideo(); }
“Clients should not be forced to depend upon interfaces that they do not use”
giovedì 30 giugno 2011
giovedì 30 giugno 2011
giovedì 30 giugno 2011
giovedì 30 giugno 2011
Liskov Substitution Principle
“Functions that use pointers or references to base classes must be able to use objects of derived
classes without knowing it.”
giovedì 30 giugno 2011
Bird Watching Gamehttp://github.com/sleli/BirdWatching
giovedì 30 giugno 2011
Il Gioco
•Simulatore di Bird Watching
•Una sorta di “battaglia navale”... ma qui gli assi sono 3 (gli uccelli volano)
giovedì 30 giugno 2011
Le Classi
giovedì 30 giugno 2011
Analisi del problema
giovedì 30 giugno 2011
Classe GameFieldResponsabilità Collaborazioni
Gestisce la collezione di BirdsDispone il campo da giocoValida il campo da giocoInizializza il campo (start)Gestisce le logiche degli shot
Classe Bird
Il refactoring verterà sulla suddivizione di responsabilità (aumentare la coesione, diminuire l’accoppiamento)
•Maggiore riuso del codice•Maggiore robusteza del programma•Minor costo del cambiamento
giovedì 30 giugno 2011
Passi di refactoring
giovedì 30 giugno 2011
Duplicazione
giovedì 30 giugno 2011
Duplicazione (semplice)
@Before public void Setup() { field = new GameField(10,5,3, new FieldSize(10,5,3)); }
giovedì 30 giugno 2011
Duplicazione (semplice)
public GameField(int width, int height, int depth, FieldSize fieldSize) { this.width = width; this.height = height; this.depth = depth; this.fieldSize = fieldSize; birds = new ArrayList<Bird>(); }
giovedì 30 giugno 2011
Duplicazione (semplice)
//Place the birds on the fields private void placeBirds(PlacingMode type) throws Exception { ... Location location = new Location(new Random().nextInt(this.width), new Random().nextInt(this.height)); bird.setLocation(location); if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(this.depth)); ... }
giovedì 30 giugno 2011
Eliminiamola!
giovedì 30 giugno 2011
Eliminiamola!@Before public void Setup() { field = new GameField(new FieldSize(10,5,3)); }
giovedì 30 giugno 2011
Eliminiamola!@Before public void Setup() { field = new GameField(new FieldSize(10,5,3)); }
public GameField(FieldSize fieldSize) { this.fieldSize = fieldSize; birds = new ArrayList<Bird>(); }
giovedì 30 giugno 2011
Eliminiamola!@Before public void Setup() { field = new GameField(new FieldSize(10,5,3)); }
public GameField(FieldSize fieldSize) { this.fieldSize = fieldSize; birds = new ArrayList<Bird>(); }
//Place the birds on the fields private void placeBirds(PlacingMode type) throws Exception {... Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.height())); bird.setLocation(location); if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(fieldSize.depth())); ... }
giovedì 30 giugno 2011
Diamo a Cesareciò che è di Cesare
giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
public class Location { int x = 0; int y = 0; public Location (int x, int y) { this.x = x; this.y = y; }
}
giovedì 30 giugno 2011
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
bird.setLocation(location);if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(this.depth));
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
bird.setLocation(location);if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(this.depth));
Bird duck = new Duck();duck.setLocation(new Location(10,5));duck.setHeight(3);
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
bird.setLocation(location);if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(this.depth));
Bird duck = new Duck();duck.setLocation(new Location(10,5));duck.setHeight(3);
int h = bird.getHeight();Location location = bird.getLocation();int x = location.x;int y = location.y;isValid = fieldSize.isWithinField(h, x, y);
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
public class Location { int x = 0; int y = 0;
int h = 0;
public Location (int x, int y) { this(x, y, 0); }
public Location (int x, int y, int z) { this.x = x; this.y = y; this.h = z; }
}
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.height()), new Random().nextInt(fieldSize.depth()));
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
public abstract class Bird { Location location; int height; public void setHeight(int height) throws Exception{ this.location.h = height; } public int getHeight() { return location.h; } public void setLocation(Location location) { this.location = location; } public Location getLocation() { return location; } public abstract void sing();}
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
private boolean isGameFieldValid(){ boolean isValid = true; for(Bird bird : birds) { int h = bird.getHeight(); Location location = bird.getLocation(); int x = location.x; int y = location.y; isValid = fieldSize.isWithinField(h, x, y); if (!isValid) break; } return isValid;}
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
private boolean isGameFieldValid(){ boolean isValid = true; for(Bird bird : birds) { Location location = bird.getLocation(); int h = location.h; int x = location.x; int y = location.y; isValid = fieldSize.isWithinField(h, x, y); if (!isValid) break; } return isValid;}
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
public boolean shot(int x, int y, int h) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { int height = bird.getHeight(); Location location = bird.getLocation(); hit = location.x == x && location.y == y && height == h; if (hit) { bird.sing(); break; } } } return hit; }
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
public boolean shot(int x, int y, int h) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { Location location = bird.getLocation(); hit = location.x == x && location.y == y && location.h == h; if (hit) { bird.sing(); break; } } } return hit; }
Diamo a Cesare ciò che è di Cesare
giovedì 30 giugno 2011
Quindi ora?public abstract class Bird { Location location; int height; public void setHeight(int height) throws Exception{ this.height = height; } public int getHeight() { return height; } public void setLocation(Location location) { this.location = location; } public Location getLocation() { return location; } public abstract void sing();}
giovedì 30 giugno 2011
Tell, don’t Askpublic boolean shot(int x, int y, int h) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { Location location = bird.getLocation(); hit = location.x == x && location.y == y && location.h == h; if (hit) { bird.sing(); break; } } } return hit; }
giovedì 30 giugno 2011
Applied
public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = shotLocation.equals(bird.getLocation()); if (hit) { bird.sing(); break; } } } return hit; }
giovedì 30 giugno 2011
Let’s apply it another time
public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = bird.wasHit(shotLocation) if (hit) { bird.sing(); break; } } } return hit; }
giovedì 30 giugno 2011
Another time too
public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = bird.wasHit(shotLocation) if (hit) { break; } } } return hit; }
giovedì 30 giugno 2011
Programmiamo ad oggetti o a tipi primitivi?
private boolean isGameFieldValid(){ boolean isValid = true; for(Bird bird : birds) { Location location = bird.getLocation(); int h = location.h; int x = location.x; int y = location.y; isValid = fieldSize.isWithinField(h, x, y); if (!isValid) break; } return isValid;}
giovedì 30 giugno 2011
e allora si fa!
private boolean isGameFieldValid(){ boolean isValid = true; for(Bird bird : birds) { isValid = fieldSize.isWithinField(bird.getLocation()); if (!isValid) break; } return isValid;}
giovedì 30 giugno 2011
Serve ancora?
private void placeBirds(PlacingMode type) throws Exception { //Random Distribution if (type == PlacingMode.Random) { for(Bird bird : birds) { Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.eighth()), new Random().nextInt(fieldSize.depth())); bird.setLocation(location); if (!(bird instanceof Chicken)) bird.setHeight(new Random().nextInt(this.depth)); } } //Custom Distribution else if (type == PlacingMode.Custom) { } }
giovedì 30 giugno 2011
E allora rimuoviamolo
private void placeBirds(PlacingMode type) throws Exception { //Random Distribution if (type == PlacingMode.Random) { for(Bird bird : birds) { Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.eighth()), new Random().nextInt(fieldSize.depth())); bird.setLocation(location); } } //Custom Distribution else if (type == PlacingMode.Custom) { } }
giovedì 30 giugno 2011
Anche il metodo
public abstract class Bird { ... public void setHeight(int height) throws Exception{ this.height = height; }
...}
giovedì 30 giugno 2011
Gli IF proprio non ci piacciono!
giovedì 30 giugno 2011
Come procediamo?
private void placeBirds(PlacingMode type) throws Exception { //Random Distribution if (type == PlacingMode.Random) { for(Bird bird : birds) { Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.eighth()), new Random().nextInt(fieldSize.depth())); bird.setLocation(location); } } //Custom Distribution else if (type == PlacingMode.Custom) { } }
giovedì 30 giugno 2011
I Passi di refactoring• Estratta responsabilità di “Random placing strategy” in
una classe
• estratta interfaccia IPlacingStrategy
• creata class NullPlacingStrategy
• creata Factory per Placing strategy
• “inlainato” metodo placeBirds
• trasformata la factory in un field ed estratto come parametro del costruttore
giovedì 30 giugno 2011
Il risultatopublic interface IPlacingStrategy {
void place(List<Bird> birds);
}
public class NullPlacingStrategy implements IPlacingStrategy {
@Override public void place(List<Bird> birds) { // Do nothing }
}
public class RandomPlacingStrategy implements IPlacingStrategy { private FieldSize fieldSize;
public RandomPlacingStrategy(FieldSize fieldSize) { this.fieldSize = fieldSize; }
@Override public void place(List<Bird> birds) { for(Bird bird : birds) { Location location = new Location(new Random().nextInt(fieldSize.width()), new Random().nextInt(fieldSize.height()), new Random().nextInt(fieldSize.depth())); bird.setLocation(location); } }
}
public class PlacingStrategyFactory {
public IPlacingStrategy create(PlacingMode type, FieldSize fieldSize) { if (type == PlacingMode.Random) { return new RandomPlacingStrategy(fieldSize); } return new NullPlacingStrategy(); }
}
giovedì 30 giugno 2011
Il risultato
public class GameField {...
public boolean startGame(PlacingMode pm) { placingStrategyFactory.create(pm, fieldSize).place(birds); gameStarted = isGameStarted(); return gameStarted; }
...}
giovedì 30 giugno 2011
Altri IF che non ci piacciono
private boolean isGameFieldValid(){ boolean isValid = true; for(Bird bird : birds) { isValid = fieldSize.isWithinField(bird.getLocation()); if (!isValid) break; } return isValid;}
giovedì 30 giugno 2011
Così è meglio
private boolean isGameFieldValid(){ boolean isValid = true; for(Bird bird : birds) { isValid = isValid && fieldSize.isWithinField(bird.getLocation()); } return isValid;}
giovedì 30 giugno 2011
Stesso discorso
public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = bird.wasHit(shotLocation) if (hit) { break; } } } return hit; }
giovedì 30 giugno 2011
Diventa
public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = hit || bird.wasHit(shotLocation) } } return hit; }
giovedì 30 giugno 2011
Di nuovo sulle responsabilità
giovedì 30 giugno 2011
Notate qualcosa?private boolean isGameFieldValid(){ boolean isValid = true; for(Bird bird : birds) { isValid = isValid && fieldSize.isWithinField(bird.getLocation()); } return isValid;}
public boolean shot(Location shotLocation) { boolean hit = false; if (gameStarted) { for(Bird bird : birds) { hit = hit || bird.wasHit(shotLocation) } } return hit; }
giovedì 30 giugno 2011
BirdListpublic class BirdList extends ArrayList<Bird> { private static final long serialVersionUID = -3323859086260693300L; public boolean areAllBirdsPlacedWithinField(FieldSize fieldSize) { boolean isValid = true; for(Bird bird : this) { isValid = isValid && fieldSize.isWithinField(bird.getLocation()); } return size() > 0 && isValid;
}
public boolean anyBirdWasHit(Location shotLocation) { boolean hit=false; for(Bird bird : this) { hit = hit || bird.wasHit(shotLocation); } return hit; }}
giovedì 30 giugno 2011
ed ecco i chiamanti
private boolean isGameStarted() { return birds.areAllBirdsPlacedWithinField(fieldSize);}public boolean shot(Location shotLocation) { return birds.anyBirdWasHit(shotLocation) && gameStarted; }
giovedì 30 giugno 2011
I Repository
http://github.com/sleli/BirdWatching
giovedì 30 giugno 2011
GRAZIE
Antonio Carpentieri (@acarpe)Stefano Leli (@sleli)
giovedì 30 giugno 2011