OOP在课堂上的混乱

时间:2013-12-21 00:31:56

标签: oop object-oriented-analysis

我来自C#背景,现在已经做了很长时间的编程了。但直到最近我才开始对我如何编程提出一些看法。显然,我的OOP非常糟糕。

我有几个问题也许有人可以帮助我。它们是基本的,但我想证实。

1-在C#中,我们可以声明类属性,如

private int _test;

并且有像

这样的setter getters
public int Test {get; set;}

现在,让我说我必须在类中使用此属性。我会用哪一个?私人或公众?或者它们都是一样的?

2-让我们说我必须实现一个执行XML解析的类。我们可以使用不同的东西作为类的输入,如“FILE PATH”。我应该将它作为一个类PROPERTY还是我应该将它作为参数传递给类中的公共函数?哪种方法更好。请检查以下

我可以创建一个类属性并像这样使用

public string FilePath {get; set;}

public int Parse()
{
    var document = XDocument.Load(this.FilePath);
    .........//Remaining code
}

或者

我可以将文件路径作为参数传递

public int Parse(string filePath)

我应该在什么基础上决定我应该制作一个属性,或者我应该传递一些东西作为论据?

我知道这些问题的解决方案,但我想知道正确的方法。如果你可以推荐一些视频讲座或书籍也会很好。

4 个答案:

答案 0 :(得分:2)

字段与属性

好像你有一些术语混淆了。

private int _test;

这是实例字段(也称为成员)。 该字段允许直接访问类内的值。

请注意,我说“在课堂内”。因为它是private,所以无法从课外访问它。这对于保留封装非常重要,这是OOP的基石。封装基本上告诉我们实例成员不能直接在类外部访问。

出于这个原因,我们创建了成员private,并提供了“设置”和“获取”变量的方法(至少:在Java中就是这样)。这些方法暴露给外界,强迫任何使用你的类的人通过你的方法而不是直接访问你的变量。

应该注意的是,当你在当前类中时,你也想要使用你的方法/属性。每次不这样做,您都有可能绕过验证规则。安全地玩,并始终使用方法而不是支持字段。

netto的结果是你可以强制你的逻辑应用于更改(设置)或检索(获取)。最好的例子是验证:通过强制人们使用您的方法,您的验证逻辑将在(可能)将字段设置为新值之前应用。

public int Test {get; set;}

这是自动实施的属性。粗略地说一个属性是一种使用get / set方法的简单方法。

在幕后,您的代码会转换为

private int _somevariableyoudontknow;

public void setTest(int t){
    this._somevariableyoudontknow = t;
}

public int getTest(){
    return this._somevariableyoudontknow;
}

所以对于吸气者和制定者来说真的非常相似。关于属性的好处在于,您可以在一行中定义您在7行中执行的操作,同时仍然保留显式getter和setter的所有可能性。

我的验证逻辑在哪里,你问? 要添加验证逻辑,您必须创建自定义实施属性

语法如下:

private int _iChoseThisName;

public int Test {
   get {
       return _iChoseThisName;
   }

   set {
       if(value > 5) { return _iChoseThisName; }
       throw new ArgumentException("Value must be over 5!");
   }
}

基本上我们所做的就是为您的getset提供实施方案。请注意value关键字!

属性可以这样使用:

var result = SomeClass.Test; // returns the value from the 'Test' property
SomeClass.Test = 10; // sets the value of the 'Test' property

最后一点注意事项:仅仅因为您拥有名为Test的属性,并不意味着支持变量名为test_test。编译器将为您生成一个变量名,以一种永远不会重复的方式作为后备字段。

XML解析

如果您希望得到第二个答案,那么您将必须展示当前架构的外观。

虽然它应该没有必要:将它作为构造函数的参数传递是最有意义的。您应该为要解析的每个文件创建一个新的XmlParser(随机名称)对象。解析后,您不想更改文件位置。

如果你想要这样做:创建一个进行解析的方法,让它将文件名作为参数,这样你仍然可以将它保留在一个调用中。

您不想创建属性,原因很简单,您可能忘记设置属性并调用解析方法。

答案 1 :(得分:1)

我可以回答你的第一个问题。你问“我必须在课堂上使用这个属性。”听起来像你需要使用私有变量。您提供的公共方法我认为只会做两件事:允许客户端设置您的一个私有变量,或允许客户端“查看”(获取)私有变量。但是如果你想“在类中使用这个属性”,那么在处理类中的数据时,私有变量应该是你的焦点。节日快乐:)

答案 2 :(得分:1)

第一个问题确实包含两个问题。

1)我是否应该使用getter和setter(Accessors和Mutators)来访问成员变量。

答案取决于变量的实现是否可能发生变化。在某些情况下,接口类型(getter返回的类型,并由setter设置)需要保持一致,但存储数据的基础机制可能会发生变化。例如,属性的类型可以是String,但实际上数据存储在更大的String的一部分中,getter提取String的那部分并将其返回给用户。

2)我应该给予财产什么样的可见性?

可见性完全取决于使用。如果该属性需要可供其他类或从基类继承的类访问,则该属性需要是公共的或受保护的。

我从未将实施暴露给外部问题。这就是说我总是在公共和受保护的数据上放置一个getter和setter,因为它有助于我确保即使底层实现发生变化,我也会保持接口相同。外部变化的另一个常见问题是,我希望有机会拦截外部用户修改属性的尝试,可能是为了防止它,但更有可能使对象处于良好或安全状态。这对于可能作为属性公开的缓存值尤其重要。考虑一个对值数组的内容求和的属性。您不希望每次引用时重新计算该值,因此您需要确定数组中元素的setter告诉对象需要重新计算总和。这样可以使计算保持最小。

我认为第二个问题是:我何时创建一个可以传递给构造函数公开的值?

取决于值的用途。我通常认为有两种不同类型的变量传递给构造函数。有助于创建对象的那些(您的XML文件路径就是一个很好的例子)和那些传入的对象,因为对象将负责管理。例如,在集合中,您通常可以使用数组初始化集合。

我遵循这些准则。

如果传入的值可以在不损坏对象状态的情况下进行更改,则可以将其设置为属性并公开显示。

如果更改传入的值会损坏对象的状态或重新定义其标识,则应将其留给构造函数初始化状态,并且不能通过属性方法再次访问。

由于OO Design中有许多不同的范例和语言,很多这些术语都令人困惑。了解OO设计中良好实践的最佳地点是从一本关于模式的好书开始。虽然所谓的四人帮http://en.wikipedia.org/wiki/Design_Patterns多年来一直是标准,但自那以后出版了许多更好的书。

以下是设计模式的几个资源:

http://sourcemaking.com/design_patterns

http://www.oodesign.com/

还有一对C#具体。

http://msdn.microsoft.com/en-us/magazine/cc301852.aspx

http://www.codeproject.com/Articles/572738/Building-an-application-using-design-patterns-and

答案 3 :(得分:1)

以下是我个人的观点,基于我在各种编程语言中的个人经验。我不认为最佳实践对于所有项目都不一定是静态的。


何时使用getter,何时直接使用私有实例变量

取决于。

你可能知道这一点,但让我们来谈谈为什么我们通常需要getter和setter而不是公共实例变量:它允许我们获得OOP的全部功能。

虽然实例变量只是一些转储内存(哑巴的数量肯定取决于你正在使用的语言),但是getter并没有绑定到特定的内存位置。 getter允许OOP hirarchy中的子项覆盖“实例变量”的行为而不受其约束。因此,如果你有interface有各种实现,有些可能使用ab实例变量,而有些可能使用IO从网络获取数据,从其他值计算,等等。

因此,getter不一定返回实例变量(在某些语言中这更复杂,例如带有virtual关键字的c ++,但我会尝试在这里与语言无关。)

为什么这与内部类行为有关?如果你有一个带有非final getter的类,getter和inner变量可能会返回不同的值。因此,如果您需要确定它是内部值,请直接使用它。但是,如果您依赖于“真实”值,请始终使用getter。

如果getter是final或者语言强制getter相等(这种情况比第一种情况更常见),我个人更喜欢直接访问私有字段;这使得代码易于阅读(imho)并且不会产生任何性能损失(不适用于所有语言)。


何时使用参数,何时使用实例变量/属性

尽可能使用参数。

绝不要将实例变量或属性用作参数。方法应尽可能独立。在您所述的示例中,参数化版本更好用imo。

Intance变量(带有getter或不带getter)是实例的属性。因为它们是实例的一部分,所以它们应该在逻辑上与它绑定。

看看你的例子。如果您听到XMLParser这个词,您对此有何看法?你认为解析器只能解析它绑定的单个文件吗?或者你认为解析器可以解析任何文件?我倾向于最后一个(另外,使用实例变量会另外杀死线程安全)。

另一个例子:您希望创建一个XMLArchiver,将多个xml文档放入一个存档中。在实现时,您将文件名作为构造函数的参数,可能会打开文件的输出流并将对它的引用存储为实例变量。然后,您多次拨打archiver.add(stuff-to-add)。如您所见,文件(因此,文件名)自然地绑定到XMLArchiver实例,而不是添加文件的方法。