Tôi đã làm việc để tái cấu trúc một số mã và tôi nghĩ rằng tôi có thể đã thực hiện bước đầu tiên xuống hố thỏ. Tôi đang viết ví dụ bằng Java, nhưng tôi cho rằng nó có thể là thuyết bất khả tri.
Tôi có một giao diện Foo
được định nghĩa là
public interface Foo {
int getX();
int getY();
int getZ();
}
Và việc thực hiện như
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;
}
Tôi cũng có một giao diện MutableFoo
cung cấp các trình biến đổi phù hợp
/**
* 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);
}
Có một vài cách triển khai MutableFoo
có thể tồn tại (Tôi chưa thực hiện chúng). Một trong số đó là
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;
}
Lý do tôi đã chia những thứ này là vì nó có khả năng như nhau cho mỗi cái được sử dụng. Có nghĩa là, nhiều khả năng là ai đó sử dụng các lớp này sẽ muốn một trường hợp bất biến, vì đó là họ sẽ muốn một trường hợp có thể thay đổi.
Trường hợp sử dụng chính mà tôi có là một giao diện được gọi là StatSet
đại diện cho các chi tiết chiến đấu nhất định cho một trò chơi (điểm nhấn, tấn công, phòng thủ). Tuy nhiên, số liệu thống kê "hiệu quả" hoặc số liệu thống kê thực tế là kết quả của các số liệu thống kê cơ bản, không bao giờ có thể thay đổi và các số liệu thống kê được đào tạo, có thể tăng lên. Hai cái này có liên quan bởi
/**
* 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);
}
cácStats được tăng lên sau mỗi trận chiến như
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);
}
nhưng chúng không tăng ngay sau trận chiến. Sử dụng một số vật phẩm, sử dụng các chiến thuật nhất định, sử dụng chiến trường thông minh đều có thể mang lại trải nghiệm khác nhau.
Bây giờ cho câu hỏi của tôi:
- Có một tên để phân chia giao diện bởi các bộ truy cập và bộ biến đổi thành các giao diện riêng biệt?
- Việc chia tách chúng theo cách này là cách tiếp cận 'đúng' nếu chúng có khả năng được sử dụng như nhau, hoặc có một mô hình khác, được chấp nhận hơn mà tôi nên sử dụng thay thế (ví dụ:
Foo foo = FooFactory.createImmutableFoo();
có thể trả vềDefaultFoo
hoặcDefaultMutableFoo
bị ẩn vìcreateImmutableFoo
trả vềFoo
)? - Có bất kỳ nhược điểm nào có thể thấy trước ngay khi sử dụng mẫu này, lưu lại để làm phức tạp hệ thống phân cấp giao diện không?
Lý do tôi bắt đầu thiết kế theo cách này là vì tôi nghĩ rằng tất cả những người thực hiện giao diện nên tuân thủ giao diện đơn giản nhất có thể, và không cung cấp gì thêm. Bằng cách thêm setters vào giao diện, bây giờ các số liệu thống kê hiệu quả có thể được sửa đổi độc lập với các phần của nó.
Tạo một lớp mới cho EffectiveStatSet
không có ý nghĩa nhiều vì chúng tôi sẽ không mở rộng chức năng theo bất kỳ cách nào. Chúng tôi có thể thay đổi việc thực hiện và tạo ra EffectiveStatSet
một hỗn hợp gồm hai loại khác nhau StatSets
, nhưng tôi cảm thấy đó không phải là giải pháp phù hợp;
public class EffectiveStatSet implements StatSet {
public EffectiveStatSet(StatSet baseStats, StatSet trainedStats) {
// ...
}
public int getHitpoints() {
return baseStats.getHitpoints() + (trainedStats.getHitpoints() / 4);
}
}