Function 函数参数是否违反封装?

Function 函数参数是否违反封装?,function,parameters,arguments,encapsulation,getter-setter,Function,Parameters,Arguments,Encapsulation,Getter Setter,这个问题通常与OOP实践有关。 假设我们有一个类,它的公共函数接受从对象外部传入的参数。这是否违反了封装本身?另一方面,为什么这种做法被如此广泛地使用?毕竟,在调用函数时,类的构造函数和成员变量是一种“旁路”。作为OOP的一个相对较新的程序员,以及我对封装的理解,我的函数参数通过setter传递到对象中,因此我只使用传入的成员变量来保留所有函数,而不使用任何参数。 我知道某些参数可以通过构造函数传入(顺便说一句,我使用依赖项注入),但是如果这些参数在对象实例化后发生变化呢?必须有一种方法在创建对

这个问题通常与OOP实践有关。 假设我们有一个类,它的公共函数接受从对象外部传入的参数。这是否违反了封装本身?另一方面,为什么这种做法被如此广泛地使用?毕竟,在调用函数时,类的构造函数和成员变量是一种“旁路”。作为OOP的一个相对较新的程序员,以及我对封装的理解,我的函数参数通过setter传递到对象中,因此我只使用传入的成员变量来保留所有函数,而不使用任何参数。 我知道某些参数可以通过构造函数传入(顺便说一句,我使用依赖项注入),但是如果这些参数在对象实例化后发生变化呢?必须有一种方法在创建对象后更改这些值。到目前为止,我发现除了使用setter来完成这项任务之外,没有其他选择,但是程序员们一直在讨论getter和setter是“邪恶的”,或者至少认为没有什么好的编程实践。 有谁能告诉我,我在哪里错过了要点,以及如何以一种干净的方式解决这个困境? 非常感谢您的支持

下面是一个使用C#的非常简单的具体示例:

我们在windows窗体项目中有一个窗体,其中包含3个文本框,分别名为textBox1、textBox2和textBox3

任务是添加textBox1和textBox2的值,并在textBox1或textBox2的值更改时,使用事件处理程序实例化的AddTextboxValues类将结果返回textBox3:

我经常看到它并询问它是否违反了封装:

public class AddTextBoxValues
{
    public double TextBoxValueSum(double textBox1value, double textBox2Value)
    {
       return textBox1value + textBox2Value;
    }
}
public class AddTextBoxValues
{
    private double textBox1Value;
    private double textBoxValue2;
    private double textBoxValue3;

    public double TextBox1Value
    {
        set { textBox1Value = value; }
    }

    public double TextBoxValue2
    {
        set { textBoxValue2 = value; }
    }

    public double TextBoxValue3
    {
        get { return textBoxValue3; }
    }


    public void TextBoxValueSum()
    {
        textBoxValue3= textBox1Value + textBoxValue2;
    }

}
根据我对封装的理解,这是我目前使用的方式:

public class AddTextBoxValues
{
    public double TextBoxValueSum(double textBox1value, double textBox2Value)
    {
       return textBox1value + textBox2Value;
    }
}
public class AddTextBoxValues
{
    private double textBox1Value;
    private double textBoxValue2;
    private double textBoxValue3;

    public double TextBox1Value
    {
        set { textBox1Value = value; }
    }

    public double TextBoxValue2
    {
        set { textBoxValue2 = value; }
    }

    public double TextBoxValue3
    {
        get { return textBoxValue3; }
    }


    public void TextBoxValueSum()
    {
        textBoxValue3= textBox1Value + textBoxValue2;
    }

}
这还有一个优点,就是可以将其注入表单构造函数中


非常感谢您的评论。

非常感谢Jon Skeet,您是一位真正的专业人士。 你准确地诊断出了我的问题,让我的眼睛睁得大大的,因为我缺乏知识,无法理解并找到解决我自己问题的方法。事实上,正是对封装和“对象状态”的更深入理解构建了我的难题中缺失的部分。
现在对我来说,一切似乎都是合乎逻辑和清晰的,我希望它将来也能帮助其他人。

这两个例子都不是面向对象编程。它们是过程编程的例子

事实上,第一个“类”只是一个名称空间包装
TextBoxValueSum
函数。 第二个“类”只是一个带有公共字段的结构(getters setter和公共字段之间没有区别)

如果你想使用真正的面向对象编程,你应该考虑对象,它们是事物的表示。 在您的情况下,我将编写类
Sum
,它是一个真实的东西,表示一个特定的Sum

class Sum {
  private double a, b;
  public Sum (double a, double b) { this.a = a; this.b = b; }
  public double value() { return this.a + this.b; }
}

如果你能给出一个具体的例子,那会很有帮助——听起来你把对象的状态和它需要处理的其他状态混淆了。(例如,日期格式化程序需要知道它要使用的格式,但随后会传递“日期到格式”,而这绝不是对象本身状态的一部分。)好吧,这是实现相同结果的两种不同方式——但您真的希望textbox值成为类状态的一部分吗?您认为在所有情况下都应该这样吗?您使用的“封装”的定义是什么,这表明使用方法参数可以“绕过”它?结果是一样的,但哪一种方法更优雅/正确?还记得我的问题是针对封装的暴力(到底是不是暴力?)。你能为我的例子说明你所说的“类的状态”和“所有情况”是什么意思吗?我指的是对象的状态,真的。为什么您认为一个对象必须更改其状态(即字段的值)才能处理数据?“所有情况”部分实际上是“你认为这是否普遍适用”?从根本上说,永远不应该使用参数的想法对我来说是一个非常非常糟糕的想法,这将使编码更加痛苦。是的,如果你有一个
加法器
类,每次你想让它加上两个数字的时候,你都可以创建一个新的对象,但是为什么你要这样做呢?但是在不了解背景的情况下很难写出具体的答案。我是否必须为每个和操作创建和处理sum类的对象?那么OOP将如何处理依赖注入呢?如果DI在OOP中很重要,那么接下来的问题就会出现:问题是在初始化时对象被注入到表单中而不知道操作数,在表单创建时只创建一次,并且需要在整个生命周期内更改输入值(这相当于窗体的生命周期)在文本框值更改时生成新的和。那么,在创建对象后如何更改值呢?您可以使用factory(它不仅可以创建
Sum
对象,还可以创建一些不同的对象,例如
Difference
等)并将其注入。
void clientFunction(NumberFactory numFactory){double sum=numFactory.sum(textBox1.value,textBox2.value).value();}