Java 是否通常认为更改对象是一种不好的做法';通过它的getter方法,它的状态是什么?
在我过去的发展过程中,我一直在思考这个问题 我有点反对这样做,我通常会声明一个单独的方法来显式处理逻辑 例如 如果一个类有一个返回对象列表的方法,我认为直接通过它的getter方法修改这个集合是个坏主意Java 是否通常认为更改对象是一种不好的做法';通过它的getter方法,它的状态是什么?,java,getter-setter,object-composition,Java,Getter Setter,Object Composition,在我过去的发展过程中,我一直在思考这个问题 我有点反对这样做,我通常会声明一个单独的方法来显式处理逻辑 例如 如果一个类有一个返回对象列表的方法,我认为直接通过它的getter方法修改这个集合是个坏主意 Public Class ReportGenerator{ private List<Configurations> configurations; List<Configuration> getConfigurations (){ re
Public Class ReportGenerator{
private List<Configurations> configurations;
List<Configuration> getConfigurations (){
return this.configurations;
}
}
我将使用以下方法:
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);
}
}
他们仍然可以使用ReportGenerator的getter方法更改配置对象的状态,我认为这是不允许的。但是,如果我们想防止这种情况发生,我们必须在ReportGenerator类中声明更多的方法,以将调用转发到配置对象,并使用防御副本
所以我的问题是,如果您有一个对象a,其中包含另一个使用composition的对象B,并且它们都有getter和setter,那么您更喜欢通过a的getter方法更改对象B的状态吗?
例如
或者您更喜欢向A添加方法来更改B的状态(基本上是将呼叫转发给B)
例如
在该方法内部,调用B.setTitle(“”)
很抱歉问了这么长的问题,我想我不太确定我到底想问什么。希望你能理解P
编写代码时,最重要的是清晰性。你可以做你需要的事情,甚至改变实例的状态,但是如果可以的话,我不会这么做。除非你有一个很好的例子,即使用惰性初始化(第一次访问它时创建一个对象或值)
最后,这取决于具体情况,但我会尽量不改变getter上的对象状态 看起来其他人也这么想 。。这可能适用于较小的类,但我会为您必须主控更复杂的对象层次结构而感到不寒而栗。想象一下,如果
A
突然有几个对象作为字段。你认为在每件衣服上都套上一个包装是个好主意吗?然后在每个对象变得更复杂时考虑这样做。有时做A.getB().getC().setThingamabob()
比写A.setSomething()
调用B.setCField()
调用C.setThingamabob()
更容易
如果您认为一个对象不应该是可变的,请删除setter。如果a
的使用者根本不需要更改B
,请不要提供getB()
方法,而是提供类似于a.setThingy()
的内容,其中未提及正在设置的内容是B
的一部分
API契约并不一定意味着类必须为其所有属性提供getter/setter。如果消费者不打算直接读取/修改属性,请不要提供这样做的方法。关于这是否是不良做法的答案是:“视情况而定” 一方面,返回对其内部状态的引用的类是一个“泄漏的抽象”。这是不好的,原因有很多:
- 在API中显示类的实现细节会鼓励依赖于这些细节,这使得更改它们变得更加困难。(这在这里不是一个绝对的问题,但是如果您设计API,使修改getter返回的内容成为更改内容的标准方式,那么这可能很难处理……)
- 如果细节显示为不可变的数据结构,客户端仍然可以看到“实时”更改,如果应用程序是多线程的,这可能是一个问题
- 如果细节显示为可变的数据结构,客户机可以直接更改类的状态,绕过任何假设检查,等等,这是类通常执行的
- 如果类在某些上下文中是“安全敏感”的,那么如果抽象存在漏洞,您就有各种额外的“向量”来破坏安全性
- 必须分配不可修改的集合包装器,并且它们添加了额外级别的方法调用
- 返回副本会导致复制数据的额外开销。在多线程环境中,在创建副本时可能需要锁定源数据结构
顺便说一下,你的问题标题和描述有误导性。比如说
getConfigurations().remove(1); //remove a configuration via a getter
这是误导。您没有“通过getter”删除配置。您正在通过getter返回的对象删除它
(我只是吹毛求疵,但如果你想让人们理解你,你需要使用他们理解的语言。)你在问从getter返回可变对象是否是个好主意。回答:有时候。你误解了这个问题。他问的是关于返回可变对象的问题。我确实理解……您可以返回可变VAT时间,但通常不会在getter中更改实例状态……这也是标题。感谢您提供的详细答案,我想这是逐案进行的,没有适合所有情况的完美设计。
reportGenerator.getConfigurations().get(0).settTitle("test");
A.getB().setTitle("");
A.setBTitle("");
getConfigurations().remove(1); //remove a configuration via a getter