在我过去的发展过程中,我一直在考虑这个问题。
我反对做这些事情,我通常会声明一个显式处理逻辑的单独方法。
E.g。
如果一个类有一个返回对象列表的方法,我认为直接通过其getter方法修改这个集合是个坏主意。
Public Class ReportGenerator{
private List<Configurations> configurations;
List<Configuration> getConfigurations (){
return this.configurations;
}
}
我认为通过以下操作是不好的做法:
getConfigurations().remove(1); //remove a configuration via a getter
我会使用以下方法:
Public Class ReportGenerator{
private List<Configurations> configurations;
public List<Configuration> getConfigurations (){
return Collections.unmodifiableList(this.configurations);
}
public void removeConfiguration(int index) //logic explicitly handle the remove
{
this.configurations.remove(index);
}
}
然而,还有一件事我想到的是,如果Configuration对象也有getter和setter,那么你就无法阻止其他人
reportGenerator.getConfigurations().get(0).settTitle("test");
他们仍然可以通过使用ReportGenerator的getter方法来更改Configuration对象的状态,我认为它不应该允许。但是如果我们想要防止这种情况,我们必须在ReportGenerator类中声明更多方法以将调用转发给Configuration对象,并使用防御性副本。
所以我的问题是,如果你有一个对象A,它包含另一个使用合成的对象B并且它们都有getter和setter,你更喜欢通过A的getter方法改变对象B的状态吗? E.g。
A.getB().setTitle("");
或者你更喜欢将方法添加到A来改变B的状态(基本上是将呼叫转发给B)
E.g。
A.setBTitle("");
在此方法内部,A调用B.setTitle(“”);
很抱歉这个问题很长,我想我不确定我想问什么。希望你能理解。 :P
答案 0 :(得分:1)
这可能适用于较小的类,但我会不知道如何构建一个更复杂的对象层次结构。想象一下,如果A
突然有几个对象作为字段。你认为围绕它们的包裹物是一个好主意吗?然后考虑这样做,因为每个对象变得更加复杂。有时候A.getB().getC().setThingamabob()
比写A.setSomething()
更容易,而B.setCField()
会调用调用C.setThingamabob()
的{{1}}。
如果您认为对象不应该是可变的,请删除setter。如果A
的消费者根本不需要更改B
,请不要提供getB()
方法,而是提供与A.setThingy()
类似的内容,其中不提及B
正在设置的内容是{{1}}的一部分。
您的API合约并不一定意味着您的类必须为其所有属性提供getter / setter。如果不希望消费者直接读取/修改属性,请不要提供这样做的方法。
答案 1 :(得分:0)
当你编写代码时,它比任何东西更清晰。你可以imo做你需要的,甚至改变实例状态但是如果可以的话我会避免这样做。除非你有一个好的情况,即使用延迟初始化(第一次访问它时创建一个对象或值)。
最后它确实取决于但我会尽量不改变getter上的对象状态。
看起来其他人也这么认为
.. When is it ok to change object state (for instance initialization) on property getter access?
答案 2 :(得分:0)
这是不好的做法的答案是:“这取决于”。
一方面,返回对其内部状态的引用的类是“漏洞抽象”。由于许多理论上的原因,这很糟糕:
在API中显示类实现细节会鼓励依赖于这些细节,这使得更改它们变得更加困难。 (这不是一个明确的问题,但是如果你设计API以便修改getter返回的东西是改变事物的标准方法,那么可能很难处理...... )
如果详细信息显示为不可变数据结构,客户端仍然可以看到“实时”更改,如果应用程序是多线程的,这可能会出现问题。
如果详细信息显示为可变数据结构,则客户端可以直接更改类的状态,绕过任何假设的检查,等等类通常执行。
如果类在某些情况下是“安全敏感的”,那么如果抽象漏洞,你就会有各种额外的“向量”来破坏安全性。
另一方面,使抽象无泄漏可能很昂贵:
必须分配不可修改的集合包装器,并且它们会增加额外级别的方法调用。
返回副本会产生复制数据的额外开销。在多线程环境中,您可能需要在复制时锁定源数据结构。
最后,如果API需要允许客户端进行更改,那么通过漏洞抽象实现它可能实际上为您提供了更简单的API设计。泄漏的问题可以通过(比如)使相关方法“包装私有”来减轻。
总而言之,这是“良好的OO设计”和实用问题之间的权衡。你需要根据具体情况权衡这些。
顺便说一句,您的问题标题和描述会产生误导。例如
getConfigurations().remove(1); //remove a configuration via a getter
这是误导。您没有“通过getter”删除配置。你是通过getter !!返回的对象删除它的。
(我在挑剔,但如果你想让别人理解你,你需要使用他们理解的语言。)