'Avoid code repetition in two different classes toString
Modeling a solution just to display(in console) the FreeCell card game,
I have two classes Home and FreeCells, both way almost similar toString implementation
output something like this
+----+----+----+----+
| 2♣ | E | E | E |
+----+----+----+----+
class Home
import java.util.HashMap;
import java.util.Stack;
public class Home {
private final int MAX_CELLS = 4;
private Stack<Card>[] homeCells;
public Home() {
this.homeCells = new Stack[4];
}
public boolean addACard(Card card) {
//...some code
}
@Override
public String toString() {
StringBuilder box = new StringBuilder();
box.append(buildHorizontalBorder());
box.append("\n");
box.append(buildContent());
box.append("\n");
box.append(buildHorizontalBorder());
return box.toString();
}
private String buildContent() {
StringBuilder contentBox = new StringBuilder();
contentBox.append("|");
for (int index = 0; index < MAX_CELLS; index++) {
contentBox.append(" ").append(this.homeCells[index] == null ? "E " : this.homeCells[index].peek().toString()).
append(" ").append("|");
}
return contentBox.toString();
}
private String buildHorizontalBorder() {
StringBuilder border = new StringBuilder();
border.append("+");
for (int i = 0; i < MAX_CELLS; i++) {
border.append("----").append("+");
}
return border.toString();
}
}
class FreeCell
import java.util.ArrayList;
import java.util.List;
public class FreeCells {
private final int MAX_CELLS = 4;
private List<Card> cells;
public FreeCells() {
this.cells = new ArrayList<>();
}
public boolean addCard(Card card) {
//...some code
}
@Override
public String toString() {
StringBuilder box = new StringBuilder();
box.append(buildHorizontalBorder());
box.append("\n");
box.append(buildContent());
box.append("\n");
box.append(buildHorizontalBorder());
return box.toString();
}
private String buildContent() {
StringBuilder contentBox = new StringBuilder();
contentBox.append("|");
for (int index = 0; index < MAX_CELLS; index++) {
contentBox.append(" ").append(index < this.cells.size() ? this.cells.get(index).toString() : "E ").append(" ").append("|");
}
return contentBox.toString();
}
private String buildHorizontalBorder() {
StringBuilder border = new StringBuilder();
border.append("+");
for (int i = 0; i < MAX_CELLS; i++) {
border.append("----").append("+");
}
return border.toString();
}
}
I am thinking of introdcuing a new class and abstract out the display logic to here
class Layout
public class Layout {
private final int MAX_CELLS = 4;
public String build(List<Card> cards) {
StringBuilder box = new StringBuilder();
box.append(buildHorizontalBorder());
box.append("\n");
box.append(buildContent(cards));
box.append("\n");
box.append(buildHorizontalBorder());
return box.toString();
}
private String buildContent(List<Card> cards) {
StringBuilder contentBox = new StringBuilder();
contentBox.append("|");
for (int index = 0; index < MAX_CELLS; index++) {
contentBox.append(" ").append(index < cards.size() ? cards.get(index).toString() : "E ").append(" ").append("|");
}
return contentBox.toString();
}
private String buildHorizontalBorder() {
StringBuilder border = new StringBuilder();
border.append("+");
for (int i = 0; i < MAX_CELLS; i++) {
border.append("----").append("+");
}
return border.toString();
}
}
Then change the method of toString of class Home to
@Override
public String toString() {
return new Layout().build(Arrays.stream(this.homeCells).filter(Objects::nonNull).map(Stack::peek).collect(Collectors.toList()));
}
Then change the method of toString of class FreeCell to
@Override
public String toString() {
return new Layout().build(this.cells)();
}
Is this correct OO way, or i can do this better some other way?
Solution 1:[1]
In my view, we can separate logic of game from cards:
FreeCellGameclass will be responsible for logic of game.Cell,FreeCellandHomeCellwill be responsible for cards.
We can extract the same logic of FreeCell and HomeCell in base class Cell. I mean methods toString() and buildHorizontalBorder(). I do not know Java, so I will show in C#. However, I will make comments how it can be converted to Java:
public abstract class Cell
{
private int MAX_CELLS = 4;
public abstract bool AddCart();
// When you add some card, you need to remove
// card from array where you took this card
public abstract bool RemoveCart(Card card);
public string toString() {
StringBuilder box = new StringBuilder();
box.Append(buildHorizontalBorder());
box.Append("\n");
box.Append(buildContent());
box.Append("\n");
box.Append(buildHorizontalBorder());
return box.ToString();
}
internal abstract string buildContent();
private string buildHorizontalBorder() {
StringBuilder border = new StringBuilder();
border.Append("+");
for (int i = 0; i < MAX_CELLS; i++)
{
border.Append("----").Append("+");
}
return border.ToString();
}
}
and its concrete implementations:
public class HomeCell : Cell // ":" extends in Java
{
// other code is omitted for the brevity
public override bool AddCart()
{ }
public override bool RemoveCart(Card card)
{ }
internal override string buildContent()
{ }
}
public class FreeCell : Cell // ":" extends in Java
{
// other code is omitted for the brevity
public override bool AddCart()
{ }
public override bool RemoveCart(Card card)
{ }
internal override string buildContent()
{ }
}
and game class is:
public class FreeCellGame
{
private HomeCell homeCell = new HomeCell();
private FreeCell freeCell = new FreeCell();
private void AddCard()
{
// your logic of game here
// here you will manipulate by calling methods of "homeCell" and
// "freeCell" to move cards from their arrays
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
