Message Chains
Penjelasan Smell
Smell ini terjadi ketika ingin mengakses sebuah method, perlu dilakukan pemanggilan dari hasil return method lainnya sehingga membentuk rantai: obj.a().b().c()
.
Perhatikan DistanceTest.java, terdapat message chaining ketika ingin mengakses latitude dan longitude.
class DistanceTest {
static BojekDriver driver;
static Destination destination;
@BeforeAll
static void init() {
driver = new BojekDriver("Amir", new Position(-6.201932, 106.781529));
destination = new Destination("Binus Anggrek", new Position(-6.201935, 106.781525));
}
@Test
void manhattan() {
DistanceCalculator calc = new Manhattan();
double result = calc.distance(
driver.getCurrentPosition().getLatitude(),
driver.getCurrentPosition().getLongitude(),
destination.getPosition().getLatitude(),
destination.getPosition().getLongitude()
);
double expected = 0.000007;
assertEquals(expected, result);
}
@Test
void euclidean() {
DistanceCalculator calc = new Euclidean();
double result = calc.distance(
driver.getCurrentPosition().getLatitude(),
driver.getCurrentPosition().getLongitude(),
destination.getPosition().getLatitude(),
destination.getPosition().getLongitude()
);
double expected = 0.000005;
assertEquals(expected, result);
}
}
class DistanceTest {
static BojekDriver driver;
static Destination destination;
@BeforeAll
static void init() {
driver = new BojekDriver("Amir", new Position(-6.201932, 106.781529));
destination = new Destination("Binus Anggrek", new Position(-6.201935, 106.781525));
}
@Test
void manhattan() {
DistanceCalculator calc = new Manhattan();
double result = calc.distance(
driver.getCurrentPosition().getLatitude(),
driver.getCurrentPosition().getLongitude(),
destination.getPosition().getLatitude(),
destination.getPosition().getLongitude()
);
double expected = 0.000007;
assertEquals(expected, result);
}
@Test
void euclidean() {
DistanceCalculator calc = new Euclidean();
double result = calc.distance(
driver.getCurrentPosition().getLatitude(),
driver.getCurrentPosition().getLongitude(),
destination.getPosition().getLatitude(),
destination.getPosition().getLongitude()
);
double expected = 0.000005;
assertEquals(expected, result);
}
}
public class BojekDriver {
private String name;
private Position currentPosition;
public BojekDriver(String name, Position currentPosition) {
super();
this.name = name;
this.currentPosition = currentPosition;
}
public String getName() {
return name;
}
public Position getCurrentPosition() {
return currentPosition;
}
}
public class BojekDriver {
private String name;
private Position currentPosition;
public BojekDriver(String name, Position currentPosition) {
super();
this.name = name;
this.currentPosition = currentPosition;
}
public String getName() {
return name;
}
public Position getCurrentPosition() {
return currentPosition;
}
}
public class Position {
private double latitude;
private double longitude;
public Position(double latitude, double longitude) {
super();
this.latitude = latitude;
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
}
public class Position {
private double latitude;
private double longitude;
public Position(double latitude, double longitude) {
super();
this.latitude = latitude;
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
}
Penyelesaian
Dilakukan Hide Delegate. Perhatikan class BojekDriver dan Destination, telah ditambahkan fungsi latitude()
dan longitude()
yang sebenarnya melakukan delegasi chaining yang dilakukan di package before. Hal ini dilakukan agar class client tidak merasakan adanya chaining, disembunyikan di dalam sini.
public class BojekDriver {
private String name;
private Position currentPosition;
public BojekDriver(String name, Position currentPosition) {
super();
this.name = name;
this.currentPosition = currentPosition;
}
public String getName() {
return name;
}
public Position getCurrentPosition() {
return currentPosition;
}
public double latitude() {
return this.getCurrentPosition().getLatitude();
}
public double longitude() {
return this.getCurrentPosition().getLongitude();
}
}
public class BojekDriver {
private String name;
private Position currentPosition;
public BojekDriver(String name, Position currentPosition) {
super();
this.name = name;
this.currentPosition = currentPosition;
}
public String getName() {
return name;
}
public Position getCurrentPosition() {
return currentPosition;
}
public double latitude() {
return this.getCurrentPosition().getLatitude();
}
public double longitude() {
return this.getCurrentPosition().getLongitude();
}
}
public class Destination {
private String name;
private Position position;
public Destination(String name, Position position) {
super();
this.name = name;
this.position = position;
}
public String getName() {
return name;
}
public Position getPosition() {
return position;
}
}
public class Destination {
private String name;
private Position position;
public Destination(String name, Position position) {
super();
this.name = name;
this.position = position;
}
public String getName() {
return name;
}
public Position getPosition() {
return position;
}
}
Alhasil, seperti yang bisa dilihat di DistanceTest.java di package after, message chain sudah tidak ada.
Tambahan
Jangan terlalu agresif mengurusi message chain karena bisa menyebabkan smell Middle Man.
Pertimbangkan mengurusi message chain bila terjadi di banyak tempat atau kebetulan ada class yang behavior-nya cocok untuk menampung method delegasi.