Saya telah bekerja pada refactoring beberapa kode, dan saya pikir saya mungkin telah mengambil langkah pertama ke lubang kelinci. Saya menulis contoh di Jawa, tapi saya kira itu bisa menjadi agnostik.
Saya memiliki antarmuka yang Foo
didefinisikan sebagai
public interface Foo {
int getX();
int getY();
int getZ();
}
Dan implementasi sebagai
public final class DefaultFoo implements Foo {
public DefaultFoo(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
private final int x;
private final int y;
private final int z;
}
Saya juga memiliki antarmuka MutableFoo
yang menyediakan mutator yang cocok
/**
* This class extends Foo, because a 'write-only' instance should not
* be possible and a bit counter-intuitive.
*/
public interface MutableFoo extends Foo {
void setX(int newX);
void setY(int newY);
void setZ(int newZ);
}
Ada beberapa implementasi MutableFoo
yang bisa ada (saya belum mengimplementasikannya). Salah satunya adalah
public final class DefaultMutableFoo implements MutableFoo {
/**
* A DefaultMutableFoo is not conceptually constructed
* without all values being set.
*/
public DefaultMutableFoo(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getX() {
return x;
}
public void setX(int newX) {
this.x = newX;
}
public int getY() {
return y;
}
public void setY(int newY) {
this.y = newY;
}
public int getZ() {
return z;
}
public void setZ(int newZ) {
this.z = newZ;
}
private int x;
private int y;
private int z;
}
Alasan saya membaginya adalah karena keduanya sama-sama memungkinkan untuk digunakan. Artinya, kemungkinan besar seseorang yang menggunakan kelas-kelas ini akan menginginkan instance yang tidak dapat diubah, karena mereka akan menginginkan yang bisa berubah.
Kasus penggunaan utama yang saya miliki adalah sebuah antarmuka yang disebut StatSet
yang mewakili detail pertempuran tertentu untuk sebuah game (hitpoint, serangan, pertahanan). Namun, statistik "efektif", atau statistik aktual, adalah hasil dari statistik dasar, yang tidak pernah dapat diubah, dan statistik terlatih, yang dapat ditingkatkan. Keduanya terkait dengan
/**
* The EffectiveStats can never be modified independently of either the baseStats
* or trained stats. As such, this StatSet must never provide mutators.
*/
public StatSet calculateEffectiveStats() {
int effectiveHitpoints =
baseStats.getHitpoints() + (trainedStats.getHitpoints() / 4);
int effectiveAttack =
baseStats.getAttack() + (trainedStats.getAttack() / 4);
int effectiveDefense =
baseStats.getDefense() + (trainedStats.getDefense() / 4);
return StatSetFactory.createImmutableStatSet(effectiveHitpoints, effectiveAttack, effectiveDefense);
}
Statistik terlatih meningkat setelah setiap pertempuran seperti
public void grantExperience() {
int hitpointsReward = 0;
int attackReward = 0;
int defenseReward = 0;
final StatSet enemyStats = enemy.getEffectiveStats();
final StatSet currentStats = player.getEffectiveStats();
if (enemyStats.getHitpoints() >= currentStats.getHitpoints()) {
hitpointsReward++;
}
if (enemyStats.getAttack() >= currentStats.getAttack()) {
attackReward++;
}
if (enemyStats.getDefense() >= currentStats.getDefense()) {
defenseReward++;
}
final MutableStatSet trainedStats = player.getTrainedStats();
trainedStats.increaseHitpoints(hitpointsReward);
trainedStats.increaseAttack(attackReward);
trainedStats.increaseDefense(defenseReward);
}
tetapi mereka tidak bertambah setelah pertempuran. Menggunakan barang-barang tertentu, menggunakan taktik tertentu, penggunaan medan perang yang cerdas semua bisa memberikan pengalaman yang berbeda.
Sekarang untuk pertanyaan saya:
- Apakah ada nama untuk memisahkan antarmuka oleh pengakses dan mutator menjadi antarmuka terpisah?
- Apakah membelah mereka dengan cara ini sebagai pendekatan yang 'benar' jika mereka sama-sama cenderung digunakan, atau apakah ada pola yang berbeda, lebih diterima yang harus saya gunakan sebagai gantinya (mis.
Foo foo = FooFactory.createImmutableFoo();
Yang bisa kembaliDefaultFoo
atauDefaultMutableFoo
tetapi disembunyikan karenacreateImmutableFoo
kembaliFoo
)? - Apakah ada kelemahan langsung untuk menggunakan pola ini, kecuali untuk memperumit hierarki antarmuka?
Alasan saya mulai mendesain dengan cara ini adalah karena saya memiliki pola pikir bahwa semua pelaksana antarmuka harus mematuhi antarmuka yang paling sederhana yang mungkin, dan tidak memberikan apa-apa lagi. Dengan menambahkan setter ke antarmuka, sekarang statistik efektif dapat dimodifikasi secara terpisah dari bagian-bagiannya.
Membuat kelas baru untuk EffectiveStatSet
itu tidak masuk akal karena kami tidak memperluas fungsionalitas dengan cara apa pun. Kita dapat mengubah implementasinya, dan membuat EffectiveStatSet
gabungan dua yang berbeda StatSets
, tetapi saya merasa itu bukan solusi yang tepat;
public class EffectiveStatSet implements StatSet {
public EffectiveStatSet(StatSet baseStats, StatSet trainedStats) {
// ...
}
public int getHitpoints() {
return baseStats.getHitpoints() + (trainedStats.getHitpoints() / 4);
}
}