清洁代码:对象应该具有公共属性吗?

时间:2010-07-07 13:23:24

标签: c# data-structures object properties abstraction

我正在阅读“清洁代码”一书,并且正在努力解决这个问题。在讨论对象和数据结构时,它说明了以下内容:

  • 对象隐藏抽象背后的数据,并公开对该数据进行操作的函数。
  • 数据结构公开其数据并且没有任何有意义的功能。

所以,我从中获得的是我不应该在我的对象上有任何公共属性,我应该只有对属性执行操作的方法。如果我确实需要访问属性,它们应该在数据结构上,可以从我对象上的方法返回?使用这种方法,似乎我需要为我的对象上的Height属性使用GetHeight()和SetHeight()方法,而不是仅使用 get set 属性。

也许我不明白究竟是什么建议,但这是我对“对象隐藏数据”的理解。如果你能帮助我理解这一点,我将非常感激!

提前致谢!

13 个答案:

答案 0 :(得分:30)

确实C#属性不是数据,是一个访问器,所以它是一个操作数据的函数。

你应该避开公共领域,而不是公共财产。

答案 1 :(得分:18)

公共财产很好。不必编写明确的GetHeight()SetHeight()方法就是属性的全部内容。 C#中的属性是不是数据;它最好被视为一对getter / setter方法。 (属性实际上被编译成生成的IL中的方法。)

可以隐藏数据,因为您可以在不更改界面的情况下更改实施。例如,您可以更改

public int Height { get; set; }

public int Height { get { return m_width; } set { m_width = value; } }

如果您确定您的对象应始终为方形。使用您的类的代码不需要任何修改。

因此,如果您的对象公开公共属性,它仍然“将数据隐藏在抽象背后并公开对该数据进行操作的函数”,如本书所推荐的那样。

答案 2 :(得分:10)

这主要是“财产”一词的另一个定义。 C#中的属性不是大多数其他语言所认为的属性。

例:
C ++公共属性是:

class foo
{
  public:
    int x;
};

C#中的相应术语将是公共字段:

class foo
{
  public int x;
}

我们在C#中命名的属性是其他语言的setter和getter:

C#:

class foo
{
  public int X { get; set; }
}

对应的C ++:

class foo
{
  private:
    int x;

  public:
    void setX(int newX) { this->x = newX; }
    int  getX() { return this->x; }
}

简而言之:
C#属性是完全正常的,只是不要盲目地默认它们设置并且不要让你的类中的每个数据字段都成为公共属性,想想你班级的用户真正需要知道什么/变化

答案 3 :(得分:9)

当您完成清洁代码后,我建议您阅读Bob Martin的另一本书:

  

Agile Principles Patterns and Practices In C#

在本书中,本书的大量内容讨论了一个案例研究,并在其中,Bob应用了清洁代码中讨论的原则。我首先阅读清洁代码,但回想起来,我认为应该首先阅读“敏捷模式......”,因为清洁代码更多是日常手册或良好软件原则的手册。

例如,在“敏捷模式...”中使用以下代码:

public class OrderData
{
public string customerId;
public int orderId;
public OrderData() {}

...

}

以下对公共数据使用的验证处理您的问题:

  

不要被公众使用冒犯   数据成员。这不是一个对象   真正意义上的。它只是一个   数据容器。它没有   需要有趣的行为   封装。制作数据   变量私有,并提供   吸气剂和制定者将是一种浪费   时间我本可以用一个结构   而不是一个班级,但我想要   OrderData通过引用传递   而不是价值。


除了:

就我个人而言,我不得不说罗伯特·马丁已经为SW开发者社区(以及Martin Fowler,Michael Feathers ......)做了大量的贡献。我认为他们必须阅读。

答案 4 :(得分:5)

虽然公共属性不是直接的代码味道,但请考虑以下文章:

Coding with Reason by Yechiel Kimchi(来自每个程序员应该知道的97件事

“......不要让对象获取信息。而是要求对象使用已有的信息进行处理。”

这不会一直发挥作用(例如,数据传输对象)。我要注意的是Inappropriate Intimacy

答案 5 :(得分:4)

属性实际上是方法 编译器编译属性以获取/设置MIL方法。

答案 6 :(得分:3)

属性本质上是Getter和Setter方法的简写。 Getter和Setter方法的要点是让对象处理对变量的任何操作,以便您可以执行任何额外的操作(例如数据验证)而不会导致不良后果。

我认为你可能会挂起自动属性,它没有支持变量,因此看起来像变量本身。

答案 7 :(得分:3)

本书试图描述一个对象不应该揭示类实际实现方式的理论。在更复杂的对象中,许多内部变量不一定从外部角度传达正确的信息,而应该只有方法对它们起作用。

然而,当你拥有简单的物体时,这个规则很难实现。在矩形的情况下,高度和宽度是用户想要知道的基本属性。由于实现这一点很简单,不使用get和set只会让你的代码变得比它需要的更复杂。

答案 8 :(得分:3)

在纯OO中,“真实对象”必须完全隐藏用于履行其职责的数据。因此,无论是公共领域,公共财产还是公共getter / setter函数,都必须避免暴露内部数据。

内部数据也是隐藏的,只是通过属性路由访问它来获取!

回答你的问题: - 如果您正在编写对象,请避免使用公共属性 - 如果您正在编写数据结构,则使用公共资产(公共领域也可以完成工作)

答案 9 :(得分:2)

使用私有字段生成公共访问者可在用户代码和类之间建立合同。理想情况下,此合同不应更改代码修订。

在C#中,强制执行合同的方式是使用interface。接口将允许您指定所需的方法和属性实现,但不允许使用字段。

此外,在.NET的各个方面,属性通常比字段更受欢迎。例如PropertyGrid控件只枚举属性,ASP.NET MVC模型类需要属性等。

答案 10 :(得分:2)

这是交易。

虽然公共变量有时可能有用,但通常最好将它们保密。

如果对象是唯一可以控制其变量的对象,那么很容易保持代码的组织。

想象一下,你想要保持0到200之间的高度。如果你有一个设置高度的方法,你可以很容易地监控它。

例如(为了速度,我将使用Java):

public void setHeight(int newHeight)
{
    if (newHeight < 0)
        height = 0;
    else if (newHeight > 200)
        height = 200;
    else
        height = newHeight
}

正如您所看到的,这种方法非常有条理和可控。

现在假设我们有一行代码可以在外部编辑此高度,因为您选择将其公开。除非您在代码之外控制它,否则您可能会得到一个与您的程序无关的高度。即使你 希望控制它,你也会重复代码。

非常基本的例子,但我认为它得到了重点。

答案 11 :(得分:1)

像这个帖子中的其他帖子一样,我会指出C#中的属性只是你提到的访问函数的特例。实际上,您可以对对象中的IL中的get_Property和set_Property方法进行处理,这些方法具有指示它们是属性的标志,对于实现add_和remove_ prefixed方法的事件也是如此。

处理抽象时的一个重要区别是设置属性是否将作用于对象,而不仅仅是更新内部状态或抛出PropertyChanged异常。

如果查看许多内部BCL对象,则以可以按任何顺序设置所有属性以配置对象的方式实现属性。如果进行了任何复杂的处理,那么通常一种描述将要发生的事情的方法是更好的选择。

答案 12 :(得分:0)

实际上通过使用属性,例如

public class Temp
{
   public int SomeValue{get;set;}
   public void SomeMethod()
   {
     ... some work
   }
}

您正在隐藏其数据,因为存在一个隐式变量来存储值集并由SomeValue属性返回。

如果你有

public class Temp
{
   private int someValue;
   public int SomeValue
   {
     get{ return this.someValue;}
     set{ this.someValue = value;}
   }
   public void SomeMethod()
   {
     this.someValue++;
   }
}

然后你会明白我的意思。您正在隐藏对象的数据someValue并使用SomeValue属性限制对它的访问。