2

你们用 get/set 吗?

 3 years ago
source link: https://www.v2ex.com/t/782167
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  程序员

你们用 get/set 吗?

  aqtata · 1 天前 · 5733 次点击
getName()/setName(value)



name()/name(value)

你们习惯用哪种?
54 条回复    2021-06-09 22:14:06 +08:00

lllllliu

lllllliu   1 天前

getName()/setName(value)

GeruzoniAnsasu

GeruzoniAnsasu   1 天前   ❤️ 1

除了 c++这种 snake_case 约定又没有 properties 写 name()来模拟它是个 property 外其它语言我其实想不到不加 get/set 的理由

cking

cking   1 天前   ❤️ 1

看楼上两位的回答 我都不知道我自己用 java 的 lambda 默认的 get/set 是不是有问题了....

Leviathann

Leviathann   1 天前 via iPhone

kotlin 里
xx.name 就等于是 xx.getName()
xx.name = "abc" 就等于是 xx.setName("abc")

xiaomingVTEX

xiaomingVTEX   1 天前

get/set java pojo,
可以看看极客时间 软件设计之美 14 面向对象之封装, 怎样的封装才算是高内聚

3dwelcome

3dwelcome   1 天前

js 的 var a = this.name; 和 this.name = value;最好。

反正 js 语言特性可以做到无感 hook,只有不支持的语言,才必须 set/get.

kop1989

kop1989   1 天前   ❤️ 1

抛开语言来探讨这个问题其实是没意义的。
楼上的回复也证明了,每种语言对于 getter 、setter 的理解与语法均不同。
所以很难定义什么叫“用 get/set”。

JamesR

JamesR   1 天前

这玩意麻烦得很,一两个人在开发的话,纯属多此一举,只有上百人那种大型项目各人写各人的类才有意义。

nerocc

nerocc   1 天前 via Android   ❤️ 4

C#里面 field 和 property 是分得很清楚的两个概念,写起来舒服很多,不需要考虑这么多 get set 的问题

Jwyt

Jwyt   1 天前

公司的项目用 getName()/setName(value)
自己的用 name(),name(string name)来做 get/set

Kasumi20

Kasumi20   1 天前

戴不戴套的问题

ychost

ychost   1 天前   ❤️ 4

这一点 C# 的 {get;set;} 把 properties 和 field 分的命名白白,java 只能 @Getter @Setter 来释放劳动力了,很多的 JSON 序列化,ORM 都是基于 get_xxx 和 set_xxx 的名字,而不是 field 的名字

Rwing

Rwing   1 天前   ❤️ 20

建议各位 java 程序员多睁开眼看看其他语言

coderxy

coderxy   1 天前

最开始写 go 的时候就纠结要不要用 set get, 后来发现去 TMD,直接写不知道有多爽。 正常业务哪有那么多需要往后拓展的需求,实在变动大了基本就是重构了。

Fule

Fule   1 天前   ❤️ 3

这方面 C# 的属性(Property)语法是真的香。

**最传统的方式:**
private int _score = 10;

public int Score
{
get
{
// potential more logic here
return _score;
}
set
{
// potential more logic here
_score = value;
}
}

**简化方式(无默认值)**
public int Score { get; set; }

**简化方式(有默认值)**
public int Score { get; set;} = 10;

**简化方式只读属性**
public int Score { get; private set; }
public int Score { get; }

**简化方式只读属性带默认值**
public int Score => 10;

题外话,C#里 `=>` YYDS

abersheeran

abersheeran   1 天前

Python 直接 property

c.k = v 就是 setter
c.k 就是 getter

iikebug

iikebug   1 天前   ❤️ 1

@Fule c#的语法真的不错

xiaomingVTEX

xiaomingVTEX   1 天前   ❤️ 1

## 摘录:14 | 面向对象之封装:怎样的封装才算是高内聚?

封装的重点在于对象提供了哪些行为,而不是有哪些数据。也就是说,即便我们把对象理解成数据加函数,数据和函数也不是对等的地位。函数是接口,而数据是内部的实现,正如我们一直说的那样,接口是稳定的,实现是易变的。

理解了这一点,我们来看一个很多人都有的日常编程习惯。他们编写一个类的方法是,把这个类有哪些字段写出来,然后,生成一大堆 getter 和 setter,将这些字段的访问暴露出去。这种做法的错误就在于把数据当成了设计的核心,这一堆的 getter 和 setter,就等于把实现细节暴露了出去。

一个正确的做法应该是,我们设计一个类,先要考虑其对象应该提供哪些行为。然后,我们根据这些行为提供对应的方法,最后才是考虑实现这些方法要有哪些字段。

封装的重点在于对象提供了哪些行为,而不是有哪些数据。也就是说,即便我们把对象理解成数据加函数,数据和函数也不是对等的地位。函数是接口,而数据是内部的实现,正如我们一直说的那样,接口是稳定的,实现是易变的。理解了这一点,我们来看一个很多人都有的日常编程习惯。他们编写一个类的方法是,把这个类有哪些字段写出来,然后,生成一大堆 getter 和 setter,将这些字段的访问暴露出去。这种做法的错误就在于把数据当成了设计的核心,这一堆的 getter 和 setter,就等于把实现细节暴露了出去。一个正确的做法应该是,我们设计一个类,先要考虑其对象应该提供哪些行为。然后,我们根据这些行为提供对应的方法,最后才是考虑实现这些方法要有哪些字段。


```
class User {
private String username;
private String password;

...

// 修改密码
public void setPassword(final String password) {
this.password = password;
}
}
```

但我们鼓励的做法是,把意图表现出来:

```
class User {
private String username;
private String password;

...

// 修改密码
public void changePassword(final String password) {
this.password = password;
}
}
```

这两段代码相比,只是修改密码的方法名变了,但二者更重要的差异是,一个在说做什么,一个在说怎么做。将意图与实现分离开来,这是一个优秀设计必须要考虑的问题。

不过,在真实的项目中,有时确实需要暴露一些数据,所以,等到你确实需要暴露的时候,再去写 getter 也不迟,你一定要问问自己为什么要加 getter 。至于 setter,首先,大概率是你用错了名字,应该用一个表示意图的名字;其次,setter 通常意味着修改,这是我们不鼓励的。

## 评论区
* 沧浪之水:
至于平时说的一些 POJO 的对象,可以看成是数据载体,是可以加 getter,setter 的(没有这些默认的 getter,setter,很多第三方的数据转化都很不方便,比如 json,sql 等)。在使用的时候,不归结为对象就可以了。

* 作者回复: 能分清楚面向对象和 Java 语言,这就是一个很好的区分。能分清楚传输数据和业务对象,这就是一个很好的区分。

3dwelcome

3dwelcome   1 天前

@xiaomingVTEX 现在 set/get 在 MVVM 中大量使用,框架可以在 set/get 上面下断点,知道变量什么时候被修改后,去通知与之关联的对象或事件。

如果类似这个作者说的,把 setpassword 改成 changepassword,那 MVVM 框架,就没办法去监控这个类里的数据变化了。

yejinmo

yejinmo   1 天前

public class CSharpIsTheBestLanguageInTheWorld
{
public string demo2 { get; private set; } = string.Empty;
}

xiaomingVTEX

xiaomingVTEX   1 天前

@3dwelcome #20 如果只是从 OOP 角度来说 get/set 是与对象的封装不符的,这样隐藏了对象的真实意图, 但是比如 java 中的 POJO 都有一个 get/set,引用下面的评论,POJO 作为了一种数据的载体,并不仅仅局限于对象的封装;
另外, 类只是对象的一种表现形式(比如 java );再者也不是非要强制把 get/set 修改掉,毕竟只是一种编程范式

wolfie

wolfie   1 天前

@Rwing
对对对 封装是原罪,就不应该有设计模式

yitingbai

yitingbai   1 天前

我有时候也挺纠结这个问题的, 最后还是发现写 get/set 跟直观一些, 代码提示更方便

xingheng

xingheng   1 天前

@Fule #15 全篇我都同意,但是最后四个字符 YYDS 是什么臭狗屎

tommyzhang

tommyzhang   1 天前

你写你的我写我的 我都不管你你管我呢?

xingheng

xingheng   1 天前

@xiaomingVTEX #18 已经很少人能把 OO 讲清楚了。


@3dwelcome #20 这和 MVVM 不冲突。

xiaomingVTEX

xiaomingVTEX   1 天前

@xingheng #27 确实, 反正万物皆对象就行了, 哈哈

walleL

walleL   1 天前

@xiaomingVTEX #18 相问下这段出处是哪里?

wanguorui123

wanguorui123   22 小时 5 分钟前 via iPhone

C# {get; set;,}
JAVA @Data

Rocketer

Rocketer   18 小时 12 分钟前 via iPhone

其实 C#的 Property 默认写法与直接用 public 的变量没什么区别。以下两行几乎是一样的。
public int SomeProperty {get; set;} = 10;
public int someField = 10;

区别在于,当你需要对值做一些处理时,比如:
private int _someField = 10;
public int SomeProperty
{
get
{
return _someField;
}
set
{
if (value >= 10)
{
_someField = value;
}
}
}
对外部来说,用法是统一的,还是 object.SomeProperty = 15;

而 Java 正好相反,为了让外部的用法统一,把原本可以直接 public 的变量也封装进了 getter/setter 方法中。

xiaomingVTEX

xiaomingVTEX   18 小时 11 分钟前

@walleL #29 极客时间 > 软件设计之美 > 14 | 面向对象之封装:怎样的封装才算是高内聚? > http://gk.link/a/10r9Q

CodeCodeStudy

CodeCodeStudy   15 小时 45 分钟前

因为 Java 的字段是不支持多态的,所以必须要用 getter/setter,不然容易出问题

jorneyr

jorneyr   15 小时 45 分钟前

Lombok 自动生成,需要的再手写覆盖,省事简洁还和手写代码效果一样。

turingli

turingli   15 小时 38 分钟前 via Android   ❤️ 1

@Fule C#10 public double Age{get;set=> field=Math.Round(value,2);} 进一步干掉字段

ikas

ikas   15 小时 36 分钟前

int _x,
getX(){return _x}
getY(){return 2_x+c.....}

如果你只是简单的,无所谓,但是 get ,set 又不是只是 1:1 对应到字段,
很多时候,set 方法还会做校验.
上面说了一堆 c#,如果写 xaml ui,那 wm 里还要抛事件.set 也是必须的

masterclock

masterclock   15 小时 3 分钟前

scala "默认" 不可变,没有 set
def 无参函数看起来就像是 val,不需要 get

kahlkn

kahlkn   14 小时 52 分钟前

@xiaomingVTEX 对于这位兄弟摘录的面向对象封装这块我觉得没有任何问题。

但是如果到了具体的业务场景的时候,我觉得可以 分为 偏业务实体 和 偏数据实体。这位兄弟中的 setPassword 我觉得属于数据实体的范畴。而 changePassword 属于业务实体的范畴。并且这类业务实体,偏向充血模型(即将具体的业务行为放入到实体中)。本人作为 java 开发,java 中的实体偏向贫血模型(即实体更偏向于作为数据的载体,具体的业务行为不放入实体中)。

至于 getter/setter 问题,反正 java 开发者必须写,除非你不打算用主流的框架。至于好处嘛,除了之前一位兄弟说的断点时可以监控外。 另外的作用就是 可以 在方法内 增加一些业务逻辑(尽管 java 中不建议这么做,但是对于一些紧急的需求修改上,可以临时的快速的搞搞,比如某个数据变形、裁切之类的,由于调用点很多一个一个改不方便,直接改 setter 中的内容,或者 getter 中的内容即可,前提评估好影响)。当然在 spring 等很多框架中,一些内部类或者包级别的类,可能有不少就直接 user.name 这样使用的。

passerbytiny

passerbytiny   14 小时 43 分钟前 via Android

用过一段时间的 name()/name(value),当然是用 lombok 自动生成的,到是挺喜欢这种用法,但是被 Jackson 等涉及到 Javabean 的工具打得头破血流,又改回去了。目前来说,大多数 Java 工具都遵循 Javabean 的 Getter/Setter 规范,虽然它们通过用手动配置的方式也能支持 name()/name(value)这种,但是基于约定优先与配置的敏捷开发思想,Java 这边还是老老实实的用 Getter/Setter (这种情况在慢慢改变,将来很有可能,在某个工具声明准备抛弃 Javabean 规范的很短时间内,Getter/Setter 就被主流工具迅速抛弃了)。


@3dwelcome 你这个是声明式切面编程,只是可选约定,不是必须遵守的约定。这种声明式编程,有两个显著缺点:一、一刀切;二、依赖外部配置。故 Java 界自从注解出来后,就不再推荐甚至抛弃了。

passerbytiny

passerbytiny   14 小时 24 分钟前 via Android

Javabean 的原始定义可以在这里下载: https://www.oracle.com/java/technologies/javase/javabeans-spec.html 。这是 1997 年的定义,而且还是 Sun 的不是 JCP 的。

需要纠正楼上的一些错误认识,Getter/Setter,或者说 JavaBean,是组件类,不是数据类。贫血领域模型这种名义上是业务类实际上是数据类的畸形结构,是 JavaBean 被滥用的表现,而不是 JavaBean 的表现。

xiaomingVTEX

xiaomingVTEX   14 小时 10 分钟前

贫血模型,充血模型, 学习了

libook

libook   13 小时 12 分钟前

是用属性还是方法,看需求。

如果说命名的话,在可读性上还是推荐代码能体现谓语、名词原型和规模(一个还是一组),而这种体现可以直接写在名字里,也可以在调用路径上,比如 name.set(),当然 A.name='jake'语法上已经隐含了谓语。

ericls

ericls   12 小时 11 分钟前 via iPhone

这个工具解决什么问题
你有没有遇到这个问题

如果遇到 为什么不用?

no1xsyzy

no1xsyzy   11 小时 55 分钟前

(setf (car xxx) yyy) ( common lisp 系)?
还是 (set-car! xxx yyy) ( scheme 系)?

janda

janda   8 小时 27 分钟前

lombok ?

fyxtc

fyxtc   7 小时 39 分钟前

兄弟你这个头像很复古,勾起了我十几年前的回忆

crclz

crclz   6 小时 35 分钟前

{get; set;}

promisenev

promisenev   6 小时 9 分钟前

case class 爽歪歪 scala 舒服

pkoukk

pkoukk   6 小时 2 分钟前

c# {get;set}
go Name() SetName()

ZhaoHuiLiu

ZhaoHuiLiu   3 小时 45 分钟前

不明白,为什么 Java 获取字符串长度是 "test".length() 而不是 "test".getLength() 不觉得别扭吗?

Fule

Fule   3 小时 19 分钟前

@xingheng sorry, YYDS means 永远的神,毕竟近几个版本更新加入了很多使用 `=>`的语法,比如

public int Add (int a, int b) => a + b;

Fule

Fule   3 小时 12 分钟前

说回来,对于楼主原始的问题,既然是用作一个方法(带括号调用),作为方法名,感觉还是带动词的名字比较合适:
getName();
setName("");

JerryCha

JerryCha   3 小时 10 分钟前

(() => ((() => SETvALUEwITHpARAMETER(name, value))(name))(value))()

aoeui

aoeui   2 小时 43 分钟前 via Android

Java: a.setValue(a.getValue() + 1);
C#: a.Value++;

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK