【问题标题】:Passing arguments between classes - use public properties or pass a properties class as argument?在类之间传递参数 - 使用公共属性或将属性类作为参数传递?
【发布时间】:2011-02-05 07:20:32
【问题描述】:

所以假设我有一个名为 ABC 的类,它有一个 Point 对象列表。

我需要用它们做一些绘图逻辑。这些 Point 对象中的每一个都有一个 Draw() 方法,该方法将由 ABC 类调用。

Draw() 方法代码需要来自 ABC 类的信息。

我只能看到两种让他们拥有此信息的方法:

  1. 让 Abc 类公开一些允许 draw() 做出决定的属性。
  2. 让 Abc 类传递给 draw() 一个充满属性的类。

两种情况下的属性是相同的,我的问题是在这种情况下首选什么。也许第二种方法更灵活?也许不吧?我在这里没有看到明显的赢家,但这肯定与我缺乏经验有关。

如果还有其他好的方法,请随时分享。

以下是两种情况:

class Abc1 {
    public property a;
    public property b;
    public property c;
    ...
    public property z;

    public void method1();
    ...
    public void methodn();
}

这是方法2:

class Abc2 {
    //here we make take down all properties

    public void method1();
    ...
    public void methodn();
}

class Abc2MethodArgs {
    //and we put them here. this class will be passed as argument to
    //Point's draw() method!
    public property a;
    public property b;
    public property c;
    ...
    public property z;
}

此外,如果这两种方法有任何“正式”名称,我想知道它们,以便我可以更好地选择标签/线程名称,因此它对于搜索目的更有用。或者随意编辑它们。

【问题讨论】:

  • 我可能只是因为这个例子而误解了你的观点,但感觉就像 ABC 应该绘制点,而不是基于 ABC 绘制自己的点。
  • 是的,我明白你的意思。我没有很好地解释自己,但是可以安全地假设 draw() 函数确实比在 ABC 中更好地位于 Point 中(实际上,我将有不同类型的点从 Point 类继承,每个点都有一个不同的绘图逻辑!)。

标签: c# java design-patterns oop properties


【解决方案1】:

最佳方法取决于 ABC 需要向 Point 实例提供的信息的性质、这些类之间关系的性质以及它们的“预期”未来。换句话说,有很多定性因素。

如果您确实将 Point 传递给 ABC 实例,不要 - 相反,为 Point 从 ABC 需要的任何东西制定一个适当的抽象,并将其封装在一个接口中。在静态方面,这类似于简单地创建一个新类来封装信息,但在动态方面则完全不同。

您不应该简单地传递 ABC 实例的原因是它会创建循环依赖项。无需过多介绍,这通常应被视为非常糟糕的事情,除非绝对必要,否则应避免。

而且,在更抽象的层面上,如果您确定这种明显的循环依赖的原因并将其排除在外 - 即创建一个接口来表示此“点的数据源”,它将更有意义并在以后启用逻辑更改ABC 必须履行的职责。此角色与“积分容器”角色不同,应该反映在您的设计中。

您也可以将参数传递给 draw() 方法 - 这可能是好是坏,取决于一堆因素。只要您考虑过其中的含义,这当然不是一件非常糟糕的事情。

【讨论】:

  • 您提出了一些非常有趣的观点。首先,您能否详细说明为什么这种循环依赖是一件坏事?在这种情况下,ABC 所做的只是对它的每个 Point 对象(作为私有实例变量存储在 ArrayList 中)执行 foreach。逻辑本身都在 Point 对象中。此外,您说“在静态术语中,这类似于简单地创建一个新类来封装信息,但在动态方面却大不相同。”为什么呢?谢谢!
  • 将“ABC 接口”传递给 Points 而不是普通的 ABC。
  • 这里有一个关于循环依赖的不错的讨论:stackoverflow.com/questions/1356304/… 关于静态-动态的区别——封装Point 所需的对ABC 中信息的访问的接口将静态(即认为类图)非常类似于您提到的 MethodArgs 类——但动态行为(想想交互图)会非常不同。特别是,信息不会从 ABC 实例复制到 MethodArgs 实例。
【解决方案2】:

创建和维护一个单独的类来在ABC 和point 之间传递状态会做更多的工作,但是如果你想将point 与ABC 解耦,这样做是值得的。

主要问题是,将它们脱钩对您来说有多重要?如果点实例了解 abc 实例在您的域中有意义,则可能不值得创建参数类,您应该选择选项 1。

【讨论】:

  • 我同意 - 如果 Points 知道 ABC 中的属性,那么通过将这些属性放在单独的类中几乎可以实现解耦。
  • 现在 Points 不知道 ABCs 的属性。我会在 ABC 中拥有公共属性,或者只是在 AbcMethodArg 上拥有公共属性,而不是两者都有(或者我不明白你的意思)。
【解决方案3】:

使用方法#2,但没有对象。直接把参数传给Draw就行了。

【讨论】:

  • 直接传递参数似乎很奇怪。如果以后我想添加更多参数,我就有大问题了..
  • 所以这让我投了反对票?提醒不要再试图帮助你。
  • 你的帖子不仅没用,而且是错误的。在行为良好的 OO 编程中,不希望直接在方法中传递属性。这就是为什么您在表单事件编程 EventArgs 而不是直接传递值本身的原因。
  • 无论如何,如果它的代表打扰你这么多,我可以把反对票拿走。但只要它让你开心:)(你必须编辑你的帖子,否则我不会改变投票)
  • @devoured:在你原来的问题中,你问的是灵活性;您没有具体说明您担心向 Draw 添加参数而不是能够(例如)使用来自 ABC 外部的 Points。
【解决方案4】:

既然Point 类和ABC 似乎必须在它们之间就绘制什么进行调解,为什么不在Point 上调用draw() 方法,将实际的ABC 对象作为参数传递. ABC 对象可以提供访问器方法(不要公开这些属性!),并且点类(或子类实现)可以决定在 ABC 上回调什么。

【讨论】:

  • 提供访问器方法和公开属性有什么区别?你的意思是只让类的客户端读取数据,而不是让它也设置它?或者您的意思是只让客户端获取“接口”而不是实际数据?
  • 它允许您在保持相同接口的同时重构类,记录访问和/或以其他方式管理对这些属性的访问。
【解决方案5】:

您可能需要考虑反转依赖关系。不是点访问来自 ABC 的属性,而是让 ABC 在每个点上调用“draw()”时(或之前)在点上设置属性。类似于在 Swing 的 JTable 中渲染单元格时使用的 Flyweight pattern(请参阅 javadoc)。您还可以考虑将Point(数据模型)与PointDrawer(可重用的渲染代码)解耦。这样,您的 Points 将不依赖于所有这些属性,只有您的 PointDrawers 会。

是的,即使您在绘图时将所有参数显式传递给每个 Point,这也是 OO 编程 - 这样,Points 完全不依赖于 ABC 或 ABC 可能的“参数传递类”。

【讨论】:

  • 关于逆向依赖,首先这似乎是一个非常有趣的想法(我没想到!)。但是现在我想起来了,这不是和拥有一个 ABCMethodArgs 类一样吗?这里会有什么优势?这里的点已经是你所说的 PointDrawers。
  • 一般来说,让类相互依赖是不好的(因为你很难重用它们或相互独立地改变它们)。如果您打算将参数更改为 Draw,那么 Steven Mackenzie 建议的方法比这个更好。我仍然怀疑 Properties 对象是否合理,因为它等同于 Steven 建议的接口,并且比它更复杂。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多