【问题标题】:What's the motivation for properties?房地产的动机是什么?
【发布时间】:2010-10-10 21:22:47
【问题描述】:

我有点困惑为什么语言有这些。我是一名 Java 程序员,在我的职业生涯初期,所以 Java 是我写的唯一语言,因为我开始真正了解它。

所以在 Java 中我们当然没有属性,我们编写 getThis() 和 setThat(...) 方法。

拥有属性我们会得到什么?

谢谢。

编辑: 另一个问题:在具有属性的语言中会出现哪些命名约定?

【问题讨论】:

  • 这个问题的小补充(不是开新的)为什么不干脆用public int age;并删除所有属性新语法。使用公共 int 年龄,您仍然可以编写“自然” person.age = 30 我读过我将允许您添加更复杂的逻辑(甚至连接到数据库)
  • 但我认为这不是放置业务逻辑(甚至根本不是逻辑)的正确位置,这就是为什么首先不是属性?
  • 另一条评论。属性是否会进入 Java 7?我有几个新功能不会让它低谷。 (如闭包)

标签: java oop properties java-7


【解决方案1】:

你觉得哪个更自然?

// A
person.setAge(25)
// B
person.age = 25;
// or
person.Age = 25; //depending on conventions, but that's beside the point

大多数人会回答 B。

它不仅是语法糖,还有助于进行反射;您实际上可以在数据和操作之间做出区别,而无需借助方法的名称。

对于不熟悉属性的人来说,这里有一个 C# 示例:

class Person
{
    public int Age
    {
        set
        {
            if(value<0)
                throw new ArgumentOutOfRangeException();

            OnChanged();
            age = value;
        }

        get { return age; }
    }

    private int age;
    protected virtual void OnChanged() { // ... }
}

此外,大多数人总是使用属性而不是稍后提升公共成员,原因与我们总是使用 get/set 的原因相同;无需重写绑定到数据成员的旧客户端代码。

【讨论】:

  • 关于反思的部分是正确的。拥有反映对象数据的属性在语义上也更重要。
  • @COincoin:为什么不只是公共成员?顺便说一句,它仍然应该是 person.age 而不是 person.Age
  • 公共成员不给你执行验证的能力
  • @Oscar...不一定...大多数 C# 样式指南(我见过)使用“Age”(Pascal 大小写)作为属性,而不是“age”(Camel 大小写)。
  • @Beska 问题发布在 Java 标记而不是 C# 标记中……Java 的命名约定是年龄。
【解决方案2】:

语法更好:

button.Location += delta;

比:

button.setLocation(button.getLocation() + delta);

【讨论】:

    【解决方案3】:

    编辑:

    下面的代码假定您是手动完成所有操作。在我的示例世界中,编译器将生成简单的 get/set 方法并将所有直接变量访问转换为这些方法。如果不这样做,则必须重新编译客户端代码,这在很大程度上违背了目的。

    原文:

    属性的主要论点是,如果您从变量转到方法,则无需重新编译代码。

    例如:

    public class Foo
    {
        public int bar;
    }
    

    如果我们后来决定对“bar”进行验证,我们需要这样做:

    public class Foo
    {
        private int bar;
    
        public void setBar(final int val)
        {
            if(val <= 0)
            {
                throw new IllegalArgumentException("val must be > 0, was: " + val);
            }
    
            bar = val;
        }
    
        public int getBar()
        {
            return (bar);
        }
    }
    

    但是添加 set/get 方法会破坏所有代码。如果它是通过属性完成的,那么您将能够在事后添加验证而不会破坏客户端代码。

    我个人不喜欢这个想法 - 我对使用注释和自动获取简单的 set/get 并能够根据需要提供自己的 set/get 实现的想法更满意(但我不像隐藏的方法调用)。

    【讨论】:

    • 这只有在属性是字节码的一部分时才有效。如果它只是语法糖,你仍然需要重新编译。例如,C# 属性是纯语法,实际上创建了一个“get_prop”类型的方法。如果在那里从字段更改为属性,仍然需要重新编译。
    • 肯定有属性客户端代码仍然需要重新编译(只是不重写)?
    • 既然你提到了注解,我就在为获得@Get、@Set 和@GetSet (... :)) 注解而大肆宣传。这意味着不需要额外的语法糖!
    • Esko - @Get/etc... 注释仍然不允许您传递属性。你最终不得不传递字符串,这使得代码变得脆弱并且重构很容易出错。
    • 想象你声明了一个像“@readonly property int foo;”这样的实例变量(property 将是 new 关键字)。那会使编译器吐出一个 getMethod(没有设置),因为它有 property 关键字它会将所有 .foo 转换为对 .getFoo() 的调用。
    【解决方案4】:

    两个原因:

    1. 干净/简洁的语法;和
    2. 它更清楚地向类的用户表明状态(属性)和行为(方法)之间的区别。

    【讨论】:

    • 我不明白你的第 2 点——例如,在 C# 中,你不能在属性中有任意代码吗?
    • 是的,但按照惯例,你不会。见stackoverflow.com/questions/601621/properties-vs-methods/…
    • @cletus:呵呵呵呵 一个非常有用的结构,建议不要使用。好吧,如果它可用,它可能会很方便(并且被滥用)
    【解决方案5】:

    在 Java 中,getter 和 setter 本质上是属性。

    在其他现代语言 (c#) 等中,它只是使语法更易于使用/理解。

    它们是不必要的,并且在大多数情况下都有解决方法。

    这确实是一个偏好问题,但如果您使用的语言支持它们,我建议您使用它们:)

    【讨论】:

      【解决方案6】:

      一开始我也为此苦苦挣扎,但我真的很欣赏它们。在我看来,属性允许我以自然的方式与公开的数据进行交互,而不会丢失 getter/setter 方法提供的封装。换句话说,我可以将我的属性视为字段,但如果我选择不公开实际字段,则不会真正公开。借助 C# 3.0 中的自动属性,对于大多数领域来说,它变得更好——我希望允许消费者读取/写入数据——我要写的更少:

      public string Prop { get; set; }
      

      在我想要部分可见性的情况下,我可以轻松地限制我想要的访问器。

      public string Prop { get; private set; }
      

      所有这些都可以通过 getter/setter 方法来完成,但措辞要高得多,用法也不太自然。

      【讨论】:

        【解决方案7】:

        面向对象编程的一般规则是永远不要更改现有接口。这确保了虽然在内部内容可能会发生变化,但调用该对象的对象不需要知道这一点。

        其他语言的属性是伪装成特定语言特征的方法。在 Java 中,属性仅通过约定进行区分。虽然通常这有效,但在某些情况下它会限制您。例如,有时您会使用 hasSomething 而不是 getSomething 的 isSomething。

        因此它允许名称的灵活性,而依赖的工具和其他代码仍然可以区分。

        此外,代码可以更紧凑,get 和 set 按设计组合在一起。

        【讨论】:

          【解决方案8】:

          面向对象的软件构造2中,Bertrand Meyer 将此称为“统一访问原则”,一般的想法是,当一个属性从一个简单的(即只是一个整数)变为派生的(函数调用),使用它的人不必知道。

          您不希望每个使用您的代码的人都必须更改

          int x = foo.y;

          int x = foo.y();

          这破坏了封装,因为你没有改变你的“接口”只是你的“实现”。

          【讨论】:

            【解决方案9】:

            您还可以创建派生字段和只读/只写字段。我在使用过的语言中看到的大多数属性不仅可以让您分配简单的字段,还可以为属性分配完整的功能。

            【讨论】:

              【解决方案10】:

              属性提供了一种简单的方法,可以将对象中一组逻辑背后的细节抽象为外部世界的单个值。

              虽然您的属性可能仅作为一个值开始,但这种抽象将接口解耦,以便以后可以更改其细节而影响最小。

              一般的经验法则是抽象和松耦合是好事。属性是实现两者的模式。

              【讨论】:

                【解决方案11】:

                语言级别的属性是个坏主意。他们没有很好的约定,他们在代码中隐藏了性能缺陷。

                【讨论】:

                  【解决方案12】:

                  一切都与绑定有关

                  曾几何时,我认为属性只是语法糖(即通过减少它们的类型来帮助开发人员)。随着我进行越来越多的 GUI 开发并开始使用绑定框架(JGoodies、JSR295),我发现语言级别的属性远不止语法糖。

                  在绑定场景中,您基本上定义了“对象 A 的属性 X 应始终等于对象 B 的属性 Y”的规则。速记是:A.x B.y

                  现在,想象一下您将如何实际使用 Java 编写绑定库。现在,绝对不可能将“x”或“y”直接称为语言原语。您只能将它们称为字符串(并通过反射访问它们)。本质上,A."x" B."y"

                  当您重构代码时,这会导致大量问题。

                  还有其他注意事项,包括正确实施属性更改通知。如果你看一下我的代码,每个有福的 setter 至少需要 3 行代码来完成非常简单的事情。再加上这 3 行中的一个包含另一个字符串:

                  public void setFoo(Foo foo){
                    Foo old = getFoo();
                    this.foo = foo;
                    changeSupport.firePropertyChange("foo", old, foo);
                  }
                  

                  所有这些四处飘荡的弦乐都是一场噩梦。

                  现在,想象一下,如果一个财产在语言中是一等公民。这开始提供几乎无限的可能性(例如,想象直接使用 Property 注册侦听器,而不是必须使用 PropertyChangeSupport,这是必须添加到每个类的 3 个神秘方法)。想象一下能够将属性本身(不是属性的值,而是 Property 对象)传递到绑定框架中。

                  对于 Web 层开发人员,想象一个 Web 框架,它可以根据属性本身的名称(例如 registerFormProperties(myObject.firstname, myObject.lastname, someOtherObject.amount) 来构建它自己的表单 id 值以允许往返当表单提交回服务器时,对象属性值的数量。现在,你必须传入字符串,重构变得很头疼(一旦你依赖字符串和反射,重构实际上变得非常可怕把东西连接起来)。

                  因此,无论如何,对于我们这些通过绑定处理动态数据更新的人来说,属性是语言中非常需要的功能 - 不仅仅是语法糖。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-04-21
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-02-22
                    • 2014-12-31
                    • 1970-01-01
                    相关资源
                    最近更新 更多