Why use getters and setters/accessors?
技术背景
在面向对象编程中,对于类的成员变量,通常有两种访问方式:直接使用公共字段(public fields)和使用访问器方法(getters 和 setters)。公共字段允许外部代码直接访问和修改类的成员变量,而访问器方法则提供了一种间接的访问和修改方式。使用 getters 和 setters 而非直接使用公共字段的优势,是一个常见的讨论话题。
实现步骤
直接使用公共字段
1 2 3
| public class Example { public String foo; }
|
使用时可以直接访问和修改:
1 2 3
| Example example = new Example(); example.foo = "bar"; String value = example.foo;
|
使用 getters 和 setters
1 2 3 4 5 6 7 8 9 10 11
| public class Example { private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; } }
|
使用时通过方法来访问和修改:
1 2 3
| Example example = new Example(); example.setFoo("bar"); String value = example.getFoo();
|
核心代码
带有验证逻辑的 setter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Example { private int speed;
public void setSpeed(int speed) { if (speed > 100) { this.speed = 100; } else { this.speed = speed; } }
public int getSpeed() { return speed; } }
|
实现接口的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public interface LiquidContainer { public int getAmountMl(); public void setAmountMl(int amountMl); public int getCapacityMl(); }
public class Bottle implements LiquidContainer { private int capacityMl; private int amountFilledMl;
public Bottle(int capacityMl, int amountFilledMl) { this.capacityMl = capacityMl; this.amountFilledMl = amountFilledMl; checkNotOverFlow(); }
public int getAmountMl() { return amountFilledMl; }
public void setAmountMl(int amountMl) { this.amountFilledMl = amountMl; checkNotOverFlow(); }
public int getCapacityMl() { return capacityMl; }
private void checkNotOverFlow() { if (amountFilledMl > capacityMl) { throw new RuntimeException("Bottle overflow"); } } }
|
最佳实践
何时使用 getters 和 setters
- 需要添加额外逻辑:如验证、计算等。例如,在设置年龄时,确保年龄在合理范围内。
- 遵循接口规范:当实现接口时,接口通常只定义方法,需要使用 getters 和 setters 来实现对字段的访问。
- 封装内部实现:隐藏类的内部表示,允许在不改变公共接口的情况下修改实现。
何时可以直接使用公共字段
- 简单的数据结构:当类只是作为简单的数据容器,不包含复杂的逻辑时,可以使用公共字段。
- 内部代码:在内部代码中,如果不需要对字段进行复杂的控制,可以暂时使用公共字段,后续根据需要再添加 getters 和 setters。
常见问题
使用 getters 和 setters 会降低性能吗?
一般情况下,使用 getters 和 setters 带来的性能开销非常小,在大多数应用中可以忽略不计。在某些性能测试中,getter 甚至可能比直接访问字段更快。
添加验证逻辑到 setter 会破坏原有的合同吗?
是的,如果在 setter 中添加验证逻辑,会改变原有的合同(即可以设置任意值的约定)。在这种情况下,可能需要修改所有使用该字段的代码。
所有字段都应该使用 getters 和 setters 吗?
不是的。如果字段不需要额外的控制或逻辑,直接使用公共字段可以使代码更简洁。过度使用 getters 和 setters 可能会导致代码变得冗长和复杂。