Organizing Data — Tasks¶
12 hands-on exercises.
Task 1 ⭐ — Replace Magic Number with Symbolic Constant (Java)¶
What is 1.07? What is 5?
Solution
Task 2 ⭐ — Encapsulate Field (Java)¶
Solution
Task 3 ⭐ — Replace Data Value with Object (Python)¶
Solution
Task 4 ⭐⭐ — Replace Type Code with Enum (Java)¶
class Order {
public static final int DRAFT = 0;
public static final int SUBMITTED = 1;
public static final int SHIPPED = 2;
private int status;
}
Solution
Task 5 ⭐⭐ — Replace Type Code with Subclasses (Java)¶
class Employee {
static final int ENGINEER = 0, SALESMAN = 1;
int type;
double commission;
double monthlyPay() {
if (type == ENGINEER) return 5000;
return 3000 + commission;
}
}
Solution
Task 6 ⭐⭐ — Encapsulate Collection (Java)¶
Solution
Task 7 ⭐⭐ — Replace Array with Object (Java)¶
String[] row = {"Alice", "Engineer", "30"};
System.out.println(row[0] + " - " + row[1] + ", " + row[2]);
Solution
Use a record (Java 14+):Task 8 ⭐⭐⭐ — Change Bidirectional to Unidirectional (Java)¶
class Order {
private Customer customer;
}
class Customer {
private Set<Order> orders = new HashSet<>();
}
If customer.orders is rarely used and a repository exists, drop it.
Solution
Task 9 ⭐⭐ — Replace Subclass with Fields (Java)¶
abstract class Person {
abstract boolean isMale();
abstract char code();
}
class Male extends Person { boolean isMale() { return true; } char code() { return 'M'; } }
class Female extends Person { boolean isMale() { return false; } char code() { return 'F'; } }
Solution
class Person {
private final boolean male;
private final char code;
private Person(boolean male, char code) { this.male = male; this.code = code; }
public static Person createMale() { return new Person(true, 'M'); }
public static Person createFemale() { return new Person(false, 'F'); }
public boolean isMale() { return male; }
public char code() { return code; }
}
Task 10 ⭐⭐⭐ — Replace Type Code with State (Java)¶
An order has DRAFT → SUBMITTED → SHIPPED transitions. Each status has different behavior for cancel(). Replace the type code with State.
Solution
interface OrderStatus {
void cancel(Order order);
String name();
}
class DraftStatus implements OrderStatus {
public void cancel(Order o) { o.setStatus(new CancelledStatus()); }
public String name() { return "DRAFT"; }
}
class SubmittedStatus implements OrderStatus {
public void cancel(Order o) {
o.refund();
o.setStatus(new CancelledStatus());
}
public String name() { return "SUBMITTED"; }
}
class ShippedStatus implements OrderStatus {
public void cancel(Order o) {
throw new IllegalStateException("Can't cancel shipped order");
}
public String name() { return "SHIPPED"; }
}
class CancelledStatus implements OrderStatus {
public void cancel(Order o) {}
public String name() { return "CANCELLED"; }
}
class Order {
private OrderStatus status = new DraftStatus();
public void setStatus(OrderStatus s) { this.status = s; }
public void cancel() { status.cancel(this); }
public void refund() { ... }
}
Task 11 ⭐⭐⭐ — Change Reference to Value (Java)¶
class Currency {
private final String code;
public Currency(String code) { this.code = code; }
public String code() { return code; }
}
// somewhere:
Currency a = new Currency("USD");
Currency b = new Currency("USD");
// a.equals(b) is false (default Object.equals)
Make Currency a value object.
Solution
public record Currency(String code) {
public Currency {
Objects.requireNonNull(code);
if (code.length() != 3) throw new IllegalArgumentException();
}
}
class Currency {
private final String code;
public Currency(String code) {
this.code = Objects.requireNonNull(code);
if (code.length() != 3) throw new IllegalArgumentException();
}
public String code() { return code; }
@Override public boolean equals(Object o) {
return o instanceof Currency c && c.code.equals(code);
}
@Override public int hashCode() { return code.hashCode(); }
@Override public String toString() { return code; }
}
Task 12 ⭐⭐⭐ — Combined: Encapsulate + Replace Data Value + Replace Type Code (Python)¶
class User:
def __init__(self):
self.email = "" # public, primitive
self.role = 0 # 0=guest, 1=member, 2=admin
self.preferences = [] # public mutable list
Apply 3 refactorings: Encapsulate Field, Replace Data Value with Object, Replace Type Code with Class.
Solution
from enum import Enum
from dataclasses import dataclass, field
class Role(Enum):
GUEST = "guest"
MEMBER = "member"
ADMIN = "admin"
@dataclass(frozen=True, slots=True)
class Email:
value: str
def __post_init__(self):
if "@" not in self.value:
raise ValueError("invalid email")
class User:
def __init__(self, email: Email, role: Role = Role.GUEST):
self._email = email
self._role = role
self._preferences: list[str] = []
@property
def email(self) -> Email:
return self._email
@property
def role(self) -> Role:
return self._role
@property
def preferences(self) -> tuple[str, ...]:
return tuple(self._preferences)
def add_preference(self, p: str) -> None:
if p not in self._preferences:
self._preferences.append(p)
Self-check¶
- ☑ I can replace primitives with proper types.
- ☑ I can pick between enum, subclass, and State for type codes.
- ☑ I can encapsulate fields and collections.
- ☑ I can decide value vs. reference semantics.
- ☑ I can convert bidirectional associations to unidirectional and back.
Next¶
- find-bug.md — wrong refactors.
- optimize.md — perf pitfalls.
- interview.md — review.