面向对象的设计 - 当一个 class 中有很多数据字段时,封装有多重要?
Object-Oriented design - how important is encapsulation when there're lots of data-fields in one class?
我有一个关于封装的问题:
当 class 有很多数据字段时,是否建议使用封装?
以下面的class为例:
abstract public class Character {
private String name;
private String characterClass;
private int level;
private int hitDice;
private int strength;
private int constitution;
private int dexterity;
private int intelligence;
private int wisdom;
private int charisma;
private int hp;
private int currentHp;
private int armorClass;
private int BaseAttackBonus;
private long xp;
private double gp;
private Inventory inventory;
private double carriedWeight;
private Equipment equipment;
protected Character(String name) {
setName(name);
setCharacterClass("Class");
setLevel(1);
setHitDice(0);
setStrength(10);
setConstitution(10);
setDexterity(10);
setIntelligence(10);
setWisdom(10);
setCharisma(10);
setHp((int) getLevel() * (getHitDice() + getModifier(getConstitution())));
setCurrentHp(getHp());
setArmorClass(10 + getModifier(getDexterity()));
setBaseAttackBonus(0);
inventory = new Inventory();
setCarriedWeight(0);
equipment = new Equipment();
setXp(0);
setGp(20);
}
protected Character(String name, int lvl) {
setName(name);
setCharacterClass("Class");
setLevel(lvl);
setHitDice(0);
setStrength(10);
setConstitution(10);
setDexterity(10);
setIntelligence(10);
setWisdom(10);
setCharisma(10);
setHp((int) getLevel() * (getHitDice() + getModifier(getConstitution())));
setCurrentHp(getHp());
setArmorClass(10 + getModifier(getDexterity()));
setBaseAttackBonus(0);
inventory = new Inventory();
setCarriedWeight(0);
equipment = new Equipment();
setXp(1000 * (getLevel() - 1));
setGp(getLevel() * 20);
}
void displayCharacter() throws IOException {
System.out.print("\n\n");
System.out.println("Name: " + getName());
System.out.println("Class: " + getCharacterClass());
System.out.println("Level: " + getLevel());
System.out.println("HP: " + getHp());
System.out.println("Current HP: " + getCurrentHp());
System.out.println("Armor Class: " + getArmorClass());
System.out.println("Base Attack Bonus : +" + getBaseAttackBonus());
System.out.println("***************");
System.out.println("Attributes: ");
System.out.println("Strength: " + getStrength());
System.out.println("Constitution: " + getConstitution());
System.out.println("Dexterity: " + getDexterity());
System.out.println("Intelligence: " + getIntelligence());
System.out.println("Wisdom: " + getWisdom());
System.out.println("Charisma: " + getCharisma());
System.out.println("***************");
equipment.showEquipment();
inventory.showInventory();
System.out.println("Carried weight: " + getCarriedWeight());
System.out.println("");
System.out.println("XP: " + getXp());
System.out.println("Gold: " + getGp());
System.out.println("");
}
public int getModifier(int number) {
int mod = (int) ((number - 10) / 2);
return mod;
}
public String getName() {
return name;
}
public String getCharacterClass() {
return characterClass;
}
public int getLevel() {
return level;
}
public int getHitDice() {
return hitDice;
}
public int getStrength() {
return strength;
}
public int getConstitution() {
return constitution;
}
public int getDexterity() {
return dexterity;
}
public int getIntelligence() {
return intelligence;
}
public int getWisdom() {
return wisdom;
}
public int getCharisma() {
return charisma;
}
public int getHp() {
return hp;
}
public int getCurrentHp() {
return currentHp;
}
public int getArmorClass() {
return armorClass;
}
public int getBaseAttackBonus() {
return BaseAttackBonus;
}
public Equipment getEquipment() {
return equipment;
}
public Inventory getInventory() {
return inventory;
}
public double getCarriedWeight() {
return carriedWeight;
}
public long getXp() {
return xp;
}
public double getGp() {
return gp;
}
protected void setName(String Name) {
name = Name;
}
protected void setCharacterClass(String characterClass) {
this.characterClass = characterClass;
}
protected void setLevel(int lvl) {
level = lvl;
}
protected void setHitDice(int hd) {
hitDice = hd;
}
protected void setStrength(int str) {
strength = str;
}
protected void setConstitution(int con) {
constitution = con;
}
protected void setDexterity(int dex) {
dexterity = dex;
}
protected void setIntelligence(int intel) {
intelligence = intel;
}
protected void setWisdom(int wis) {
wisdom = wis;
}
protected void setCharisma(int cha) {
charisma = cha;
}
protected void setHp(int hitPoints) {
hp = hitPoints;
}
protected void setCurrentHp(int curHp) {
currentHp = curHp;
}
protected void setArmorClass(int ac) {
armorClass = ac;
}
protected void setBaseAttackBonus(int bab) {
BaseAttackBonus = bab;
}
protected void setXp(int XP) {
xp = XP;
}
protected void setGp(double GP) {
gp = GP;
}
protected void setCarriedWeight(double weight) {
carriedWeight = weight;
}
public void attack(Character target) {
try {
((Weapon) getEquipment().getPrimaryHand()).attack(this, target);
} catch (NullPointerException e) {
getEquipment().equipPrimaryHand(
MeleeWeapon.meleeWeaponList.get(0)); /* equip fist weapon */
((Weapon) getEquipment().getPrimaryHand()).attack(this, target);
if (target.getCurrentHp() <= 0) {
System.out.println(target.getName() + " is down !");
}
}
}
public void equip() {
getInventory().equip(this);
}
public void addToInventory(Item newItem) {
getInventory().addToInventory(this, newItem);
}
}
考虑将大部分数据字段存储在不同的 class 中,例如 strength
和 constitution
中的 Stats
class作为更好的设计?
对象有行为。对象内的状态支持该行为。分离出一堆状态,简单地作为状态的容器,而不是一个具有自己特定行为的独特对象,在事物的大局中没有多大意义。
我认为您指的是 decomposition - 将大型系统分解为更小、更易于理解的部分的行为。
要正确分解你的代码,你必须关注cohesion:你的class代表了多少东西?他们 "stick" 在一起有多好?
你的class目前代表了很多东西:
- 角色身份信息,例如
name
- 技能跟踪器,例如
constition
- 体验追踪器
- 库存
- 个人体重秤
您的 1 class 代表多个实体;它具有低内聚性。
所以为了回答您的问题,是的,将与统计相关的字段移动到统计 class 是一件好事。但这不仅仅是您应该移动的领域,而是整个责任。这意味着如果你有一个 resetStats()
方法,它也会转到 Stat
class.
如果被移动的成员是private
,分解有助于进一步封装,因为它进一步隐藏了信息。但分解是它自己的主题。
我有一个关于封装的问题:
当 class 有很多数据字段时,是否建议使用封装?
以下面的class为例:
abstract public class Character {
private String name;
private String characterClass;
private int level;
private int hitDice;
private int strength;
private int constitution;
private int dexterity;
private int intelligence;
private int wisdom;
private int charisma;
private int hp;
private int currentHp;
private int armorClass;
private int BaseAttackBonus;
private long xp;
private double gp;
private Inventory inventory;
private double carriedWeight;
private Equipment equipment;
protected Character(String name) {
setName(name);
setCharacterClass("Class");
setLevel(1);
setHitDice(0);
setStrength(10);
setConstitution(10);
setDexterity(10);
setIntelligence(10);
setWisdom(10);
setCharisma(10);
setHp((int) getLevel() * (getHitDice() + getModifier(getConstitution())));
setCurrentHp(getHp());
setArmorClass(10 + getModifier(getDexterity()));
setBaseAttackBonus(0);
inventory = new Inventory();
setCarriedWeight(0);
equipment = new Equipment();
setXp(0);
setGp(20);
}
protected Character(String name, int lvl) {
setName(name);
setCharacterClass("Class");
setLevel(lvl);
setHitDice(0);
setStrength(10);
setConstitution(10);
setDexterity(10);
setIntelligence(10);
setWisdom(10);
setCharisma(10);
setHp((int) getLevel() * (getHitDice() + getModifier(getConstitution())));
setCurrentHp(getHp());
setArmorClass(10 + getModifier(getDexterity()));
setBaseAttackBonus(0);
inventory = new Inventory();
setCarriedWeight(0);
equipment = new Equipment();
setXp(1000 * (getLevel() - 1));
setGp(getLevel() * 20);
}
void displayCharacter() throws IOException {
System.out.print("\n\n");
System.out.println("Name: " + getName());
System.out.println("Class: " + getCharacterClass());
System.out.println("Level: " + getLevel());
System.out.println("HP: " + getHp());
System.out.println("Current HP: " + getCurrentHp());
System.out.println("Armor Class: " + getArmorClass());
System.out.println("Base Attack Bonus : +" + getBaseAttackBonus());
System.out.println("***************");
System.out.println("Attributes: ");
System.out.println("Strength: " + getStrength());
System.out.println("Constitution: " + getConstitution());
System.out.println("Dexterity: " + getDexterity());
System.out.println("Intelligence: " + getIntelligence());
System.out.println("Wisdom: " + getWisdom());
System.out.println("Charisma: " + getCharisma());
System.out.println("***************");
equipment.showEquipment();
inventory.showInventory();
System.out.println("Carried weight: " + getCarriedWeight());
System.out.println("");
System.out.println("XP: " + getXp());
System.out.println("Gold: " + getGp());
System.out.println("");
}
public int getModifier(int number) {
int mod = (int) ((number - 10) / 2);
return mod;
}
public String getName() {
return name;
}
public String getCharacterClass() {
return characterClass;
}
public int getLevel() {
return level;
}
public int getHitDice() {
return hitDice;
}
public int getStrength() {
return strength;
}
public int getConstitution() {
return constitution;
}
public int getDexterity() {
return dexterity;
}
public int getIntelligence() {
return intelligence;
}
public int getWisdom() {
return wisdom;
}
public int getCharisma() {
return charisma;
}
public int getHp() {
return hp;
}
public int getCurrentHp() {
return currentHp;
}
public int getArmorClass() {
return armorClass;
}
public int getBaseAttackBonus() {
return BaseAttackBonus;
}
public Equipment getEquipment() {
return equipment;
}
public Inventory getInventory() {
return inventory;
}
public double getCarriedWeight() {
return carriedWeight;
}
public long getXp() {
return xp;
}
public double getGp() {
return gp;
}
protected void setName(String Name) {
name = Name;
}
protected void setCharacterClass(String characterClass) {
this.characterClass = characterClass;
}
protected void setLevel(int lvl) {
level = lvl;
}
protected void setHitDice(int hd) {
hitDice = hd;
}
protected void setStrength(int str) {
strength = str;
}
protected void setConstitution(int con) {
constitution = con;
}
protected void setDexterity(int dex) {
dexterity = dex;
}
protected void setIntelligence(int intel) {
intelligence = intel;
}
protected void setWisdom(int wis) {
wisdom = wis;
}
protected void setCharisma(int cha) {
charisma = cha;
}
protected void setHp(int hitPoints) {
hp = hitPoints;
}
protected void setCurrentHp(int curHp) {
currentHp = curHp;
}
protected void setArmorClass(int ac) {
armorClass = ac;
}
protected void setBaseAttackBonus(int bab) {
BaseAttackBonus = bab;
}
protected void setXp(int XP) {
xp = XP;
}
protected void setGp(double GP) {
gp = GP;
}
protected void setCarriedWeight(double weight) {
carriedWeight = weight;
}
public void attack(Character target) {
try {
((Weapon) getEquipment().getPrimaryHand()).attack(this, target);
} catch (NullPointerException e) {
getEquipment().equipPrimaryHand(
MeleeWeapon.meleeWeaponList.get(0)); /* equip fist weapon */
((Weapon) getEquipment().getPrimaryHand()).attack(this, target);
if (target.getCurrentHp() <= 0) {
System.out.println(target.getName() + " is down !");
}
}
}
public void equip() {
getInventory().equip(this);
}
public void addToInventory(Item newItem) {
getInventory().addToInventory(this, newItem);
}
}
考虑将大部分数据字段存储在不同的 class 中,例如 strength
和 constitution
中的 Stats
class作为更好的设计?
对象有行为。对象内的状态支持该行为。分离出一堆状态,简单地作为状态的容器,而不是一个具有自己特定行为的独特对象,在事物的大局中没有多大意义。
我认为您指的是 decomposition - 将大型系统分解为更小、更易于理解的部分的行为。
要正确分解你的代码,你必须关注cohesion:你的class代表了多少东西?他们 "stick" 在一起有多好?
你的class目前代表了很多东西:
- 角色身份信息,例如
name
- 技能跟踪器,例如
constition
- 体验追踪器
- 库存
- 个人体重秤
您的 1 class 代表多个实体;它具有低内聚性。
所以为了回答您的问题,是的,将与统计相关的字段移动到统计 class 是一件好事。但这不仅仅是您应该移动的领域,而是整个责任。这意味着如果你有一个 resetStats()
方法,它也会转到 Stat
class.
如果被移动的成员是private
,分解有助于进一步封装,因为它进一步隐藏了信息。但分解是它自己的主题。