Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 避免setter更改类的值';s属性_Oop_Encapsulation_Setter_Getter Setter - Fatal编程技术网

Oop 避免setter更改类的值';s属性

Oop 避免setter更改类的值';s属性,oop,encapsulation,setter,getter-setter,Oop,Encapsulation,Setter,Getter Setter,我有一个带有一个私有字段的类: class Person { string name; public void setName(string name); } 然后,使用负责与用户交互的某个对象(在本例中是通过命令行),我想更改此字段的值: Person somePerson; CommandLineView view; somePerson.setName(view.askUserForName()); 它起作用了。但是我不喜欢使用set函数,因为它会暴露类成员。 因此,我开始考虑

我有一个带有一个私有字段的类:

class Person {
  string name;
  public void setName(string name);
}
然后,使用负责与用户交互的某个对象(在本例中是通过命令行),我想更改此字段的值:

Person somePerson;
CommandLineView view;
somePerson.setName(view.askUserForName());
它起作用了。但是我不喜欢使用
set
函数,因为它会暴露类成员。 因此,我开始考虑如何避免它

新的实现如下所示:

class Person
{
  string name;
  public void changeName(view) { name = view.askUserForName(); }
}
以及:

现在
Person
不公开其成员。此外,此类负责与更改名称相关的逻辑(例如,函数
changeName
还可以更新数据库、通知相关方等)


问题是:这种重构是一种好的实践吗?或者使用
setter
实现更好,即使它破坏了封装?

我认为根本不应该有方法来设置名称,它应该是一个构造函数参数:

Person somePerson(view.askUserForName());
您的方法存在的问题是,您首先创建的对象没有完全初始化,因此使用它是危险的:
Person somePerson
。如果您忘记了
设置名称
,您的代码还会与这个“空”人一起工作吗

然后允许直接用
setName
方法修改内部状态,这也不好

使用构造函数参数可以避免这两个问题

至于最初的问题——我不认为这两种方法之间有太大的区别。 结果完全相同-您调用该方法并且内部对象状态已更改。您可以将其命名为
setName
changeName
,结果相同

使用
changeName(view)
的第二种方法实际上更糟糕,因为还引入了
Person
view
对象的依赖关系。
现在,如果你想更改名称,你总是需要先创建
视图
对象。

不知道这个问题是否适合这里-但我认为你现在使用它的方式确实将
方式与
命令行视图
紧密结合起来-最好有一个setter或只是一个
更改名称
方法(取新名称)-视图取决于模型是可以的(显然)但另一个方向是一个巨大的警告标志!你为什么不想公开姓名?@Carsten-那么你认为在
person
view
之间插入一个新层怎么样,例如一些演示者?@SimonWood-公开私有字段不被认为是一种代码气味吗?在我看来
p之间几乎没有区别public
字段和
private
一个带有setter和/或getter的字段。为什么要使用另一个间接层?我想你会想在模型和视图中使用演示者-因此你会让视图依赖于模型和演示者,演示者依赖于模型和视图…什么都没有得到-抱歉,我只是不知道是什么你不想要接吻设定者^^-这是一种符合我品味的创业方式。软件中可以存在没有名字的人!例如,我可以代表我从窗口看到的人-我对他们的外表了解很多,但只有在打开窗口并提出要求后我才能知道他们的名字;)但这不是讨论的重点。我同意,也许依赖于
视图是不好的。也许它应该依赖于像
NameChanger
这样的东西。我读过一篇Yegor Bugayenko的文章:我遵循这句话:“一个对象可以被其他对象撕裂,因为它们可以通过setter将任何新数据注入其中。该对象无法足够安全地封装自己的状态,因为任何人都可以更改它。”这里的关键字是“安全”-我相信只允许指定的对象更改
Person
的状态有助于避免一些错误。@PiotrAleksanderChmielowski我认为你是在欺骗自己,想找到一种奇特的方法来为一个名字设置一个setter,而这篇文章说的是你应该完全避免设置setter。这里有一句话:
狗是一个不可变的生命体,它不允许外界的任何人改变它的体重、大小、名字等。
。基本上,如果您有任何形式的getter和setter,这与将
name
字段声明为
public
person->name=“New name”
是一样的。看起来不好吗?基本上,如果你有一个getter和setter,以任何形式,这就等同于将提交的名称声明为公共“我同意!但是我不认为在我的问题的
changeName(view)
中有一个隐藏的
setter
name
的值正在
Person
类中更改。它不是从外部更改的。@PiotrAleksanderChmielowski,但随后有人更改了
view=newcommandlineview(“新名称”);人员->更改姓名(视图),如果这是可能的,那么您实际上有一个setter。
Person somePerson(view.askUserForName());