3

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

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

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

谢谢。

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

4

12 回答 12

9

你觉得哪一个更自然?

// 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 的原因相同;无需重写绑定到数据成员的旧客户端代码。

于 2009-03-02T22:02:58.500 回答
7

语法更好:

button.Location += delta;

比:

button.setLocation(button.getLocation() + delta);
于 2009-03-02T22:04:03.863 回答
6

编辑:

下面的代码假定您是手动完成所有操作。在我的示例世界中,编译器将生成简单的 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/geterate 的想法更满意,并且能够根据需要提供自己的 set/get 实现(但我不喜欢隐藏的方法来电)。

于 2009-03-02T22:10:18.653 回答
3

两个原因:

  1. 清洁/简洁的语法;和
  2. 它更清楚地向类的用户表明状态(属性)和行为(方法)之间的区别。
于 2009-03-02T22:01:14.603 回答
2

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

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

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

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

于 2009-03-02T22:06:41.937 回答
1

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

public string Prop { get; set; }

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

public string Prop { get; private set; }

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

于 2009-03-02T22:07:12.247 回答
1

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

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

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

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

于 2009-03-02T22:10:18.747 回答
1

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

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

诠释 x = foo.y;

int x = foo.y();

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

于 2009-03-02T23:01:26.237 回答
0

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

于 2009-03-02T22:08:02.840 回答
0

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

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

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

于 2009-03-02T22:13:19.473 回答
0

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

于 2009-03-03T22:28:38.320 回答
0

一切都与绑定有关

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

在绑定场景中,您基本上定义了“对象 A 的属性 X 应始终等于对象 B 的属性 Y”的规则。简写是:Ax <-> By

现在,想象一下您将如何实际使用 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 个神秘方法)。想象一下能够将属性本身(不是属性的值,而是属性对象)传递到绑定框架中。

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

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

于 2009-03-05T06:12:22.347 回答