2010-07-07 74 views
26

我正在阅读“清洁代码”一书,并且正在与一个概念挣扎。在讨论对象和数据结构时,它声明以下内容:清洁代码:对象是否具有公共属性?

  • 对象将其数据隐藏在抽象背后并暴露对这些数据进行操作的函数。
  • 数据结构暴露他们的数据并且没有有意义的功能。

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

也许我并不完全了解正在建议的内容,但这是我对“对象的理解”。如果你能帮助我理解这一点,我将不胜感激!

在此先感谢!

+2

要添加到使用公用propertiers下面的答案,这种混淆可能源于许多语言不支持属性的事实。在这种情况下,您可以在访问方法和公共字段之间进行选择,正确的选择始终是访问方法。 C#没有这个问题,因为它支持属性。 – 2010-07-07 13:40:07

回答

17

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

数据隐藏是可能的,因为您可以在不更改接口的情况下更改实现。例如,你可以改变

public int Height { get; set; } 

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

,如果你决定,你的目标应该始终不散。使用你的类的代码不需要任何修改。

所以如果你的对象暴露了公有属性,它仍然“隐藏它的数据在抽象之后,并暴露了对这些数据进行操作的函数”,正如书中的建议。

4

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

30

事实上,一个C#属性不是数据,是一个访问器,所以它是一个对数据进行操作的函数。

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

+3

是的,但公用字段在数据传输对象上是可以的 – 2010-07-07 14:19:33

+2

我避免了DTO,但是在特定的情况下。当必须使用它们时,我更喜欢自动属性。 – onof 2010-07-07 15:02:43

+0

对于几乎所有的项目,没有理由偏好属性而不是字段,以及喜欢字段的几个理由。字段为:[1]保证行为(改变属性以添加行为需要重新编译,这是*好的*); [2]有时更快,永远不会更慢; [3]代码较短; [4]可以是'readonly',它比'get'只有更强的保证。如果您正在编写一个公共API,其中的属性需要允许在将来版本中的行为与二进制兼容或需要私有setter(但考虑使用“readonly”),则只能使用属性。 – 2013-01-24 12:19:24

2

使用私人字段生成公共访问器会在用户代码和您的类之间建立一个契约。理想情况下,这个合同不应该修改代码。

在C#中,执行合同合规的方式是使用interface。接口将允许您指定所需的方法和属性实现,但不允许使用字段。另外,在.NET的各个不同点上,属性通常比字段更受欢迎。例如PropertyGrid控制只枚举的属性,ASP.NET MVC模型类需要的属性等

3

属性基本上为getter和setter方法手短。 Getter和Setter方法的意义在于让对象处理对变量的任何操作,以便您可以执行任何额外操作(如数据验证)而不会产生不必要的后果。

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

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属性限制对其的访问。

3

这本书试图描述的理论,一个对象不应该暴露如何实际实现类。在更复杂的对象中,许多内部变量并不一定从外部角度传达正确的信息,而应该只有对它们采取行动的方法。

但是,当你拥有简单的物体时,制定这条坚硬而快速的规则会分崩离析。在矩形的情况下,高度和宽度是用户希望知道的基本属性。而且由于这个实现很直接,所以不使用get和set会让你的代码比它需要的更复杂。

10

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

实施例:
A C++公共属性是:

class foo 
{ 
    public: 
    int x; 
}; 

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

class foo 
{ 
    public int x; 
} 

我们在C#名称类型作为属性将是制定者和其他语言的获得者:

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#属性是完全没事,只是不要盲目默认他们得到集,不要使每一个数据字段在类中公共财产,想想你的班级的用户真的需要知道/改变。

1

像这个线程中的其他帖子我会指出,在C#中的属性只是你提到的访问函数的特例。事实上,您可以在对象中的IL中修改get_Property和set_Property方法,该方法有一个标志,指示它们是属性,对于实现add_和remove_前缀方法的事件也是如此。

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

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

9

当您完成清洁守则,我建议你读鲍勃·马丁公司的另一本书:

Agile Principles Patterns and Practices In C#

在这本书的书广大ammount的讨论一个案例研究,并在其中, Bob应用Clean Code中讨论的原则。我首先阅读Clean Code,但回想起来我认为应该先阅读“敏捷模式”,因为Clean Code更像是一本日常手册或手册中的优秀SW原则。

例如,在“敏捷模式......”下面的代码被用于:

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

... 

} 

使用公共数据涉及您的问题的下列验证:

别使用公众 数据成员不会被冒犯。这不是 真正意义上的对象。它仅仅是一个用于数据的容器 。它没有 有趣的行为,需要封装 。使数据变得私密,并且提供 获取者和设置者将是浪费时间的 。我可以使用结构 而不是类,但我希望 OrderData通过引用 而不是按值传递。


旁白:

就个人而言,我不得不说,罗伯特·马丁已经向SW开发者社区一个巨大的贡献(与马丁·福勒,迈克尔羽毛一起。)这些书。我认为他们必须阅读。

+0

还有[清洁编码](http://www.amazon.com/The-Clean-Coder-Professional-Programmers/dp/0137081073) - 不同的主题,但很值得阅读恕我直言。 – TrueWill 2013-07-04 15:00:39

2

这是交易。

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

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

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

例如(我将使用Java进行速度的缘故):

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

正如你所看到的,这种做法是很有条理和控制。

现在想象一下,我们有一行代码在外部编辑这个高度,因为您选择公开它。除非您在代码之外控制它,否则您可能会得到一个与您的程序不相符的高度。即使你没有想要控制它,你会重复代码。

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

5

虽然公共属性不是立即码味,认为这篇文章:

Coding with Reason by Yechiel Kimchi(从书97件事每个程序员都应该知道

” ......不问对象让信息与之合作,而是要求对象用已有的信息完成工作。“

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

+2

+1为报价挂在我的桌子上!感谢您的参考。 – JSprang 2010-07-07 18:02:17

+0

这是严格的OOP方法。在某些情况下很难实现。考虑MVVM模式。 – onof 2010-07-09 20:40:59

3

在纯粹的面向对象中,“一个真实的对象”必须完全隐藏它用来履行责任的数据。因此,无论是通过公共领域,公共领域还是公共的getter/setter函数来完成,都必须避免暴露内部数据。

内部数据也没有隐藏只是通过路由访问它通过一个属性被抽象!

要回答你的问题: - 避免公共属性,如果你正在写一个对象 - 如果你正在写的数据结构(公共领域会做的工作,太)