C#中getter和setter的更好替代方法是什么?

时间:2012-08-29 22:11:20

标签: c# oop accessor

我已经阅读了一些关于在面向对象编程中使用getter / setter的一些内容,并且许多资源(例如this)表明它们应该很少使用。该文章的一句话说:

  

不要求您提供完成工作所需的信息;询问有信息的对象为你做的工作。

虽然原则上听起来不错,但我并不确定如何最好地实施。说我有一节课描述了一辆车。在那个班级里面,我们可以说这辆车的品牌是“丰田”。现在我有一个想要显示这是“丰田”的GUI。没有吸气剂,如何做到这一点?

即使我抽象出“丰田”作为一个字符串存储并返回一个已经写入“丰田”的TextBox,这听起来最好像原始属性的包装形式的吸气剂。我只是认为像TextBoxes这样的东西应该只在GUI的类中,而不是像我的汽车类这样的辅助类。

4 个答案:

答案 0 :(得分:3)

那篇文章描述了你应该使用方法而不是属性getter / setter。基本上它建议一个方法应该执行一个动作来修改状态而不是允许一个setter来修改状态。例如我可以上一个有月和日属性的课程。然后我可以使用代码执行此操作:

obj.Day = 28;
obj.Month = Months.February;
obj.Day = 30;
obj.Month = Months.March;

当我将一天设定为30而月份为二月时,我的状态无效。

文章建议一个类不应该允许这类事物,而是提供特定的方法来执行特定的操作,例如:

obj.ChangeDate(Months.March, 30);

如果日期时间类比由于DateTime而令人困惑,那么你可能会有类似的lat / long coords示例:

obj.Latitude = 45.4112;
obj.Longitude = -75.6981;
//... 
obj.Latitude = 39.73;
obj.Longitude = -86.27;

当纬度设置为39.73时,该位置将成为纽瓦克附近的地方,而不是渥太华(第一个纬度/长度)或印第安纳波利斯(第二个纬度/长度)。保留lat / long的设置会使接口处于打开状态,无法验证其不变量,有些人可能会说不是真正面向对象的。所以,你可能会有一个方法:

obj.MoveTo(39.73, -86.27);

OO意味着封装状态和行为。虽然某些属性可以“封装”状态,但它们通常不会。它们将实现与接口分离,以便用作属性的后备存储的内容可以改变 - 但是,它很少会发生;所以这些属性只是提供实现细节而不是提供公共字段。

有一些概念,如命令查询分离,建立在这个想法上,建议接口应该更新状态或查询状态,但不能同时更新状态或查询状态。具有getter和setter的属性提供了一个更新状态和查询状态的接口。以上示例MoveToChangeDate将是“命令”。从概念上讲,你会提供其他查询状态的方法;如果需要的话。

属性的另一个问题是人们习惯性地添加getter和setter只是因为它是属性。获取或设置属性的能力可能不是必需的,只需通过死记硬背创建和接口添加getter和setter,这需要可能不需要的测试和维护。

微妙?当然;但他谈的是面向对象的设计,而不是“正常工作”的代码。

答案 1 :(得分:2)

你忽略了“做这项工作”。如果您想要完成的工作是汽车的品牌,那么返回品牌的吸气剂就可以完成工作。

文章的内容是,如果你想在课堂数据上完成工作,把工作放在课堂上。不要从类中提取数据,对其进行处理,然后将其返回到类中:

var c = new Car();
c.Odometer += 10;  // bad
c.DriveMiles(10);  // good

我还质疑该文章对C#的适用性;它声称:

Getter和setter方法(也称为访问器)是危险的,原因与公共字段是危险的相同:它们提供对实现细节的外部访问。

在C#中这是错误的,C#访问器可以接受任意类,它们不“提供对实现细节的外部访问”。

答案 2 :(得分:1)

吸气剂和制定者不是邪恶的,它们不应该为每个属性自动生成。就你的例子而言,Car类应该有一个返回String的getBrand方法,但可能不需要这个属性的setter。 Car返回带有品牌名称的TextBox的方法最有可能比返回String的简单getter更糟糕,因为它不是非常通用的。

我现在可以看到Peter Ritchie的答案:使用changeDate的好例子。 Date类应该提供这样的方法,而不是提供日期和月份的getter,并要求用户代码在日历中自己计算第二天。

答案 3 :(得分:1)

基本上他说的是,假设你有一个有10个属性的类,并且你想将它转储到csv行。在类中添加一个Tocsv方法,以返回一个包含一堆csvs的字符串。不要编写通过属性访问它的其他类,并构建csv字符串,因为它们必然会紧密耦合。

不确定为什么他会选择访问器,这个问题与使用离散方法得到和设置完全相同,或者更糟糕的是成员变量。

显然有限制,你必须有充分的理由替换

SomeLabel.Text = SomeInstance.StringValue;

SomeInstance.MakeStringValueALabel(SomeLabel);