【问题标题】:SRP without violating encapsulationSRP 不违反封装
【发布时间】:2012-11-20 22:49:03
【问题描述】:

我在协调单一职责原则和封装时遇到了麻烦。似乎在类之间划分职责需要公开大量数据。例如,考虑一个名为DataPoints 的对象。 DataPoints 填充了 x 和 y 坐标等。我可以创建一个填充DataPoints 的生成器类。现在,假设我想绘制这些数据点。显然,这是一个单独的职责,可能来自名为DataPointsPlotter 的类。但要绘制数据,我需要知道内部 x 和 y 坐标是什么。一个班级同时处理这两个问题,这没问题。 x 和 y 是内部变量,但 create() 和 print() 方法都可以访问这些变量。我可以公开 x 和 y(也许通过 getters/setters--ugh),或者我可以将 DataPoints 结构传递给 Plotter 类,但它仍然需要进入内部才能获取 x 和 y。我可以在 DataPoints 类中声明一个 Plotter 实例,我将 x 和 y 发送到该类。但这仍然是一个曝光。

在这个例子中,我怎样才能在不违反封装的情况下使用绘图仪绘制 x 和 y?

【问题讨论】:

  • 有人愿意解释这里的反对意见吗?据我所知,我用研究过的术语甚至是一个例子提出了一个直接、可回答的问题。
  • 没有解释的单票否决通常被认为是统计噪音。有人不喜欢该帖子的某些内容,但由于不明显,可以忽略。

标签: language-agnostic encapsulation single-responsibility-principle


【解决方案1】:
class DataPoint {

    protected x, y

    public function construct(theX, theY) {
        x = theX
        y = theY
    }

    public function getX {
        return x
    }

    public function getY {
        return y
    }

}

这封装了以已知格式表示数据点的责任。假设还进行了一些健全性检查以确认 xy 具有良好的值,这是此处封装的一项职责。

class Plotter {

    public function plot(DataPoint dp) {
        x = dp.getX
        y = dp.getY

        ... plot ...
    }

}

绘图仪接受DataPoint 的实例并绘制它。这也是一项职责:绘制DataPoint 的实例。它不需要Plotter 了解DataPoint内部结构。它只需要一个已定义且稳定的接口,Plotter 如何从DataPoint 获取必要的数据。哪些是吸气剂 getXgetY。你可以随意改变DataPoint 的内部结构,只要它的interface 保持不变。 DataPoint 的职责是保存一个数据点并让其他代码以定义的方式访问其数据。如果无法从DataPoint 中获取数据,那么它的存在将毫无用处。

所以不,SRP 和封装并不矛盾。你只需要明确责任到底是什么。

【讨论】:

  • 对,我知道我可以使用 getter 和 setter(我在最初的问题中提到了它们),但我觉得它们不舒服。对我来说,他们似乎违反了告诉,不问的原则。没有 SRP,就不需要 getter/setter,因为我告诉班级进行绘图,而其他人不必知道 x 和 y,无论 getter/setter 是什么。 SRP 和 Tell, Don't Ask 是矛盾的吗?
  • 啊,这一切的运作方式让我震惊。我不需要避免在课堂上使用其他方法。我只需要避免在那里实施它们。例如。 draw 可以是一个方法,但它接受一个 DataPointDrawer 对象作为参数。这样,职责在类之间被分离,并且数据被封装。这里有很好的建议:stackoverflow.com/a/5788248/429596
  • 嗯,这取决于你想让你的课程做什么。像DataPoint 这样的类的典型职责是以定义的格式 存储值。该类有责任确保它包含有效值,但仅此而已。然后当然需要允许其他代码访问这些值,否则它是毫无意义的。为此,它需要有一个定义好的接口,其中的方法是好的。也许您的语言还允许像方法一样访问属性,即语法糖。
  • 可以向你的DataPoint 类添加一个方法public plot(Plotter p),将一个绘图仪传递给DataPoint 对象,让它调用绘图仪并将其传递给它价值观。不过这非常复杂,这意味着DataPoint 现在还需要知道如何使用Plotter。这完全不在其职责范围内。你还需要为它定义一个接口,plot(Plotter p) 方法。无论哪种方式,您都需要接口。更通用的做法是允许 any 其他类以定义的方式从DataPoint 获取数据。
  • 好点。让我怀疑DataPoint 本身是否就是设计缺陷。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-22
  • 2017-06-03
  • 2019-03-18
  • 1970-01-01
  • 2020-07-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多