V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
aqtata
V2EX  ›  程序员

你们用 get/set 吗?

  •  
  •   aqtata · 2021-06-08 15:05:01 +08:00 · 8587 次点击
    这是一个创建于 1262 天前的主题,其中的信息可能已经有所发展或是发生改变。
    getName()/setName(value)



    name()/name(value)

    你们习惯用哪种?
    58 条回复    2021-06-15 14:52:50 +08:00
    lllllliu
        1
    lllllliu  
       2021-06-08 15:06:03 +08:00
    getName()/setName(value)
    GeruzoniAnsasu
        2
    GeruzoniAnsasu  
       2021-06-08 15:08:41 +08:00   ❤️ 1
    除了 c++这种 snake_case 约定又没有 properties 写 name()来模拟它是个 property 外其它语言我其实想不到不加 get/set 的理由
    cking
        3
    cking  
       2021-06-08 15:09:54 +08:00   ❤️ 1
    看楼上两位的回答 我都不知道我自己用 java 的 lambda 默认的 get/set 是不是有问题了....
    Leviathann
        4
    Leviathann  
       2021-06-08 15:11:30 +08:00 via iPhone
    kotlin 里
    xx.name 就等于是 xx.getName()
    xx.name = "abc" 就等于是 xx.setName("abc")
    xiaomingVTEX
        5
    xiaomingVTEX  
       2021-06-08 15:21:15 +08:00
    get/set java pojo,
    可以看看极客时间 软件设计之美 14 面向对象之封装, 怎样的封装才算是高内聚
    3dwelcome
        6
    3dwelcome  
       2021-06-08 15:25:09 +08:00
    js 的 var a = this.name; 和 this.name = value;最好。

    反正 js 语言特性可以做到无感 hook,只有不支持的语言,才必须 set/get.
    kop1989
        7
    kop1989  
       2021-06-08 15:38:24 +08:00   ❤️ 1
    抛开语言来探讨这个问题其实是没意义的。
    楼上的回复也证明了,每种语言对于 getter 、setter 的理解与语法均不同。
    所以很难定义什么叫“用 get/set”。
    JamesR
        8
    JamesR  
       2021-06-08 15:42:22 +08:00
    这玩意麻烦得很,一两个人在开发的话,纯属多此一举,只有上百人那种大型项目各人写各人的类才有意义。
    nerocc
        9
    nerocc  
       2021-06-08 15:44:37 +08:00 via Android   ❤️ 4
    C#里面 field 和 property 是分得很清楚的两个概念,写起来舒服很多,不需要考虑这么多 get set 的问题
    Jwyt
        10
    Jwyt  
       2021-06-08 15:56:42 +08:00
    公司的项目用 getName()/setName(value)
    自己的用 name(),name(string name)来做 get/set
    Kasumi20
        11
    Kasumi20  
       2021-06-08 15:57:26 +08:00
    戴不戴套的问题
    ychost
        12
    ychost  
       2021-06-08 16:00:44 +08:00   ❤️ 4
    这一点 C# 的 {get;set;} 把 properties 和 field 分的命名白白,java 只能 @Getter @Setter 来释放劳动力了,很多的 JSON 序列化,ORM 都是基于 get_xxx 和 set_xxx 的名字,而不是 field 的名字
    Rwing
        13
    Rwing  
       2021-06-08 16:24:54 +08:00   ❤️ 21
    建议各位 java 程序员多睁开眼看看其他语言
    coderxy
        14
    coderxy  
       2021-06-08 16:28:22 +08:00
    最开始写 go 的时候就纠结要不要用 set get, 后来发现去 TMD,直接写不知道有多爽。 正常业务哪有那么多需要往后拓展的需求,实在变动大了基本就是重构了。
    Fule
        15
    Fule  
       2021-06-08 16:35:58 +08:00   ❤️ 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
        16
    abersheeran  
       2021-06-08 16:46:16 +08:00
    Python 直接 property

    c.k = v 就是 setter
    c.k 就是 getter
    iikebug
        17
    iikebug  
       2021-06-08 17:17:13 +08:00   ❤️ 1
    @Fule c#的语法真的不错
    xiaomingVTEX
        18
    xiaomingVTEX  
       2021-06-08 17:22:35 +08:00   ❤️ 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 语言,这就是一个很好的区分。能分清楚传输数据和业务对象,这就是一个很好的区分。
    lscexpress
        19
    lscexpress  
       2021-06-08 17:34:41 +08:00
    @Leviathann 在 php 里面也是
    3dwelcome
        20
    3dwelcome  
       2021-06-08 17:55:18 +08:00
    @xiaomingVTEX 现在 set/get 在 MVVM 中大量使用,框架可以在 set/get 上面下断点,知道变量什么时候被修改后,去通知与之关联的对象或事件。

    如果类似这个作者说的,把 setpassword 改成 changepassword,那 MVVM 框架,就没办法去监控这个类里的数据变化了。
    yejinmo
        21
    yejinmo  
       2021-06-08 20:00:15 +08:00
    public class CSharpIsTheBestLanguageInTheWorld
    {
    public string demo2 { get; private set; } = string.Empty;
    }
    xiaomingVTEX
        22
    xiaomingVTEX  
       2021-06-08 21:17:09 +08:00
    @3dwelcome #20 如果只是从 OOP 角度来说 get/set 是与对象的封装不符的,这样隐藏了对象的真实意图, 但是比如 java 中的 POJO 都有一个 get/set,引用下面的评论,POJO 作为了一种数据的载体,并不仅仅局限于对象的封装;
    另外, 类只是对象的一种表现形式(比如 java );再者也不是非要强制把 get/set 修改掉,毕竟只是一种编程范式
    wolfie
        23
    wolfie  
       2021-06-08 21:45:48 +08:00
    @Rwing
    对对对 封装是原罪,就不应该有设计模式
    yitingbai
        24
    yitingbai  
       2021-06-08 21:48:27 +08:00
    我有时候也挺纠结这个问题的, 最后还是发现写 get/set 跟直观一些, 代码提示更方便
    xingheng
        25
    xingheng  
       2021-06-08 22:02:47 +08:00
    @Fule #15 全篇我都同意,但是最后四个字符 YYDS 是什么臭狗屎
    tommyzhang
        26
    tommyzhang  
       2021-06-08 22:11:50 +08:00
    你写你的我写我的 我都不管你你管我呢?
    xingheng
        27
    xingheng  
       2021-06-08 22:17:56 +08:00
    @xiaomingVTEX #18 已经很少人能把 OO 讲清楚了。


    @3dwelcome #20 这和 MVVM 不冲突。
    xiaomingVTEX
        28
    xiaomingVTEX  
       2021-06-08 22:53:25 +08:00
    @xingheng #27 确实, 反正万物皆对象就行了, 哈哈
    walleL
        29
    walleL  
       2021-06-08 23:51:30 +08:00
    @xiaomingVTEX #18 相问下这段出处是哪里?
    wanguorui123
        30
    wanguorui123  
       2021-06-09 02:52:32 +08:00 via iPhone
    C# {get; set;,}
    JAVA @Data
    Rocketer
        31
    Rocketer  
       2021-06-09 06:45:41 +08:00 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
        32
    xiaomingVTEX  
       2021-06-09 06:46:17 +08:00
    @walleL #29 极客时间 > 软件设计之美 > 14 | 面向对象之封装:怎样的封装才算是高内聚? > http://gk.link/a/10r9Q
    CodeCodeStudy
        33
    CodeCodeStudy  
       2021-06-09 09:12:44 +08:00
    因为 Java 的字段是不支持多态的,所以必须要用 getter/setter,不然容易出问题
    jorneyr
        34
    jorneyr  
       2021-06-09 09:12:46 +08:00
    Lombok 自动生成,需要的再手写覆盖,省事简洁还和手写代码效果一样。
    turingli
        35
    turingli  
       2021-06-09 09:19:23 +08:00 via Android   ❤️ 1
    @Fule C#10 public double Age{get;set=> field=Math.Round(value,2);} 进一步干掉字段
    ikas
        36
    ikas  
       2021-06-09 09:20:59 +08:00
    int _x,
    getX(){return _x}
    getY(){return 2_x+c.....}

    如果你只是简单的,无所谓,但是 get ,set 又不是只是 1:1 对应到字段,
    很多时候,set 方法还会做校验.
    上面说了一堆 c#,如果写 xaml ui,那 wm 里还要抛事件.set 也是必须的
    masterclock
        37
    masterclock  
       2021-06-09 09:54:00 +08:00
    scala "默认" 不可变,没有 set
    def 无参函数看起来就像是 val,不需要 get
    kahlkn
        38
    kahlkn  
       2021-06-09 10:05:12 +08:00
    @xiaomingVTEX 对于这位兄弟摘录的面向对象封装这块我觉得没有任何问题。

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

    至于 getter/setter 问题,反正 java 开发者必须写,除非你不打算用主流的框架。至于好处嘛,除了之前一位兄弟说的断点时可以监控外。 另外的作用就是 可以 在方法内 增加一些业务逻辑(尽管 java 中不建议这么做,但是对于一些紧急的需求修改上,可以临时的快速的搞搞,比如某个数据变形、裁切之类的,由于调用点很多一个一个改不方便,直接改 setter 中的内容,或者 getter 中的内容即可,前提评估好影响)。当然在 spring 等很多框架中,一些内部类或者包级别的类,可能有不少就直接 user.name 这样使用的。
    passerbytiny
        39
    passerbytiny  
       2021-06-09 10:14:00 +08:00 via Android
    用过一段时间的 name()/name(value),当然是用 lombok 自动生成的,到是挺喜欢这种用法,但是被 Jackson 等涉及到 Javabean 的工具打得头破血流,又改回去了。目前来说,大多数 Java 工具都遵循 Javabean 的 Getter/Setter 规范,虽然它们通过用手动配置的方式也能支持 name()/name(value)这种,但是基于约定优先与配置的敏捷开发思想,Java 这边还是老老实实的用 Getter/Setter (这种情况在慢慢改变,将来很有可能,在某个工具声明准备抛弃 Javabean 规范的很短时间内,Getter/Setter 就被主流工具迅速抛弃了)。


    @3dwelcome 你这个是声明式切面编程,只是可选约定,不是必须遵守的约定。这种声明式编程,有两个显著缺点:一、一刀切;二、依赖外部配置。故 Java 界自从注解出来后,就不再推荐甚至抛弃了。
    passerbytiny
        40
    passerbytiny  
       2021-06-09 10:33:46 +08:00 via Android
    Javabean 的原始定义可以在这里下载: https://www.oracle.com/java/technologies/javase/javabeans-spec.html 。这是 1997 年的定义,而且还是 Sun 的不是 JCP 的。

    需要纠正楼上的一些错误认识,Getter/Setter,或者说 JavaBean,是组件类,不是数据类。贫血领域模型这种名义上是业务类实际上是数据类的畸形结构,是 JavaBean 被滥用的表现,而不是 JavaBean 的表现。
    xiaomingVTEX
        41
    xiaomingVTEX  
       2021-06-09 10:46:51 +08:00
    贫血模型,充血模型, 学习了
    libook
        42
    libook  
       2021-06-09 11:45:32 +08:00
    是用属性还是方法,看需求。

    如果说命名的话,在可读性上还是推荐代码能体现谓语、名词原型和规模(一个还是一组),而这种体现可以直接写在名字里,也可以在调用路径上,比如 name.set(),当然 A.name='jake'语法上已经隐含了谓语。
    ericls
        43
    ericls  
       2021-06-09 12:45:53 +08:00 via iPhone
    这个工具解决什么问题
    你有没有遇到这个问题

    如果遇到 为什么不用?
    no1xsyzy
        44
    no1xsyzy  
       2021-06-09 13:02:36 +08:00
    (setf (car xxx) yyy) ( common lisp 系)?
    还是 (set-car! xxx yyy) ( scheme 系)?
    janda
        45
    janda  
       2021-06-09 16:30:38 +08:00
    lombok ?
    fyxtc
        46
    fyxtc  
       2021-06-09 17:18:09 +08:00
    兄弟你这个头像很复古,勾起了我十几年前的回忆
    crclz
        47
    crclz  
       2021-06-09 18:22:33 +08:00
    {get; set;}
    promisenev
        48
    promisenev  
       2021-06-09 18:48:02 +08:00
    case class 爽歪歪 scala 舒服
    pkoukk
        49
    pkoukk  
       2021-06-09 18:55:04 +08:00
    c# {get;set}
    go Name() SetName()
    ZhaoHuiLiu
        50
    ZhaoHuiLiu  
       2021-06-09 21:12:37 +08:00
    不明白,为什么 Java 获取字符串长度是 "test".length() 而不是 "test".getLength() 不觉得别扭吗?
    Fule
        51
    Fule  
       2021-06-09 21:38:27 +08:00
    @xingheng sorry, YYDS means 永远的神,毕竟近几个版本更新加入了很多使用 `=>`的语法,比如

    public int Add (int a, int b) => a + b;
    Fule
        52
    Fule  
       2021-06-09 21:45:19 +08:00
    说回来,对于楼主原始的问题,既然是用作一个方法(带括号调用),作为方法名,感觉还是带动词的名字比较合适:
    getName();
    setName("");
    JerryCha
        53
    JerryCha  
       2021-06-09 21:47:03 +08:00
    (() => ((() => SETvALUEwITHpARAMETER(name, value))(name))(value))()
    aoeui
        54
    aoeui  
       2021-06-09 22:14:06 +08:00 via Android
    Java: a.setValue(a.getValue() + 1);
    C#: a.Value++;
    tctc4869
        55
    tctc4869  
       2021-06-10 14:10:58 +08:00
    java 的 get/set 规比后来新生语言里的 set/get 规范差是肯定
    wangshanshan
        56
    wangshanshan  
       2021-06-10 17:48:12 +08:00
    @xiaomingVTEX 对于这个,理论上确实应该如此。可是在实际上,由于项目的中的对象各有不同,它所拥有的字段也各有不同,使用 get/set 可以通用于所有字段,如果给封装对象行为的名字 ,太过于独特
    Amit
        57
    Amit  
       2021-06-10 18:23:05 +08:00
    get/set 并不等价于获取 /设置变量值,里面是可以有逻辑的,比如前端传的一个非必填的参数,我可以在 get 方法里设置默认值(这不符合贫血模型但这种逻辑写到 service 中就太丑了),还有一些框架序列化或反序列化的时候使用 get/set 命名规则,不按这个来会出问题
    myCupOfTea
        58
    myCupOfTea  
       2021-06-15 14:52:50 +08:00
    java get/set 命名还不是早期不支持 proxy 吗,
    像 js,python 这种天生支持 get/set,还非要用 get/set 干嘛呢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   965 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 21:32 · PVG 05:32 · LAX 13:32 · JFK 16:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.