【问题标题】:Single Responsibility Principle in OOPOOP 中的单一职责原则
【发布时间】:2011-11-16 19:38:34
【问题描述】:

在我的应用程序设计中,我通常将对象映射到数据库中的重要表。然后对象处理与该数据相关的所有内容(包括链接表)。例如,我构建了一个Activity 对象,具有namedue_date 等属性,load()save() 等方法,以及getParent()getContributors()getTeam() 等方法返回(数组)其他对象。这是因为它违反了单一职责原则,所以这是“坏”的 OOP 吗?

【问题讨论】:

  • 你会如何回答“班级负责什么?”这个问题
  • 我想到了这一点,这让我想到了这个问题。我想说:处理与活动有关的一切。但我不确定这是否有效:)
  • 感谢您提出有趣的问题。不是关于“如何对数组进行排序”,就像其他许多人一样:)

标签: php oop single-responsibility-principle


【解决方案1】:

这取决于情况和您拥有的确切代码:您的设计可能涉及多个职责,但仍然是一个非常好的 OOP 且可维护。

您是否使用相似代码在每个类中处理load()save()?或者您是否将load()save() 中的任务委派 给在多个类中用于此功能的其他对象?这将是 SRP 之后的一半,但仍符合您的设计。

如果没有,您的代码确实看起来有点臭。要检查它是否涵盖多个职责,请问问自己:什么可能导致我的课程发生变化?在您的情况下,我至少会尝试重构 @987654325 中的类似代码@和save()在不同的类中达到上述情况,这样

  • 可维护性大大提高,
  • 您仍然不需要更改客户的代码。

【讨论】:

  • 确实如此。将数据库交互方法提取到另一个类中,从而创建数据访问层。然后,您的业务逻辑将驻留在模型中,您的数据库交互将驻留在其他地方。
  • 我认为load()save() 的代码重用是一个很好且重要的主题,但对于另一个问题。模型可以根据需要与 DB 一起使用 - 使用代码重用(ORM、Mapper)或不使用 - 取决于具体情况下哪个更好。在这个问题中,我认为主题是与其他模型、依赖项和责任合作。
  • 我认为责任、依赖、代码重用、可维护性,它们都是相互关联的。你不应该仅仅因为 SRP 被认为是好的而遵循它,而要记住为什么会这样(ergo 谈论可维护性和代码重用)。
  • 我认为它是可维护的。几乎没有重复,我确实使用了数据库抽象层。在load() 方法中,我只运行(特定于类的)查询来获取数据,进行一些预处理,例如在name 等文本属性中转义HTML 字符,并将数据分配给对象的属性。
  • 如果您没有用于预处理的重复/类似代码,那么我会说您具有良好的 OOP 并充分遵循了 SRP。 SRP 也不是您必须 100% 遵守的严格规则,而是一个指导方针。要了解这一点,您可以在 hanselminutes 和 stackoverflow/stackexchange 播客上收听与 Bob 大叔关于 SOLID 设计原则的辩论。
【解决方案2】:

嗯..在这个阶段很难说。你可以把整个班级都过去,但是..

是的,它看起来像糟糕的 OOP。您有同一个类负责与数据库和域逻辑的交互。这就产生了两个完全不同的类改变的原因。

您可能会从探索DataMapper 模式中受益。

【讨论】:

  • 我会看看 DataMapper 模式,谢谢。但是,为什么类可以通过查询来“填充自己”呢?我知道它如何使测试变得更加困难,但从设计的角度来看它有什么问题?
  • @Rijk 汽车可以自己添加引擎吗?这与其说是“设计”问题,不如说是“常识”问题。
  • 关于汽车和发动机的类比错误。模型可以在没有 DataMapper 的情况下与 DB 一起工作,并且可以与他一起工作——这两种情况都没有错。这只是意味着,如果我们可以在这种情况下使用 DataMapper 进行代码重用。
  • @OZ_ ,没有人谈论任何关于 models 的事情。但在本例中,模型将是 Automobile Plant(工厂 - 工厂的另一个词 .. 以避免混淆)。
  • @tereško,对不起,我还是不明白你的想法。或许你能解释的更详细一点?
【解决方案3】:

也许我会在黑暗中踢这个(因为我不是专家)但是:

域对象中的方法 load() 和 save() 称为 Active Record (Another description)。这还不错(尽管我不喜欢它),因为可能会在您之后或与您一起工作的人在弄清楚如何持久化这些对象方面会遇到更少的问题。

关于其他方法。如果它在对象域中并代表对象行为,那还不错。如果设计得好,它可能会非常好。 Domain driven design 鼓励使用与贫血域模型相反的富域模型。 anemic domain model 的域对象只有属性、getter 和 setter。因此,只要它在您的对象的域中,在其中添加其他方法就不会被认为是坏事。

这是我从我读过的书籍和文章中理解的那些概念..

希望对你有帮助。

【讨论】:

【解决方案4】:

您描述的是 ActiveRecord,众所周知它违反了 SRP。此外,ActiveRecord 仅在表行与对象紧密匹配时才能正常工作。一旦阻抗失配变得太大,以后对系统进行更改就会变得更加困难。

这不一定是糟糕的 OOP,但它是Technical Debt 的一种形式,因为持久性逻辑和域逻辑之间缺乏分离。违反任何 SOLID 原则通常会导致代码难以更改、代码脆弱、代码不可重用。

其中一些债务不是问题。当这些债务累积利息时,例如当他们开始影响其他设计决策时。换句话说,当您发现更改系统变得更加困难时,请尝试偿还一些债务,例如重构为更可维护的解决方案。

【讨论】:

  • Martin Fowler 真的被引用了很多 :)
  • @Rijk 很好,他写了很多有意义的东西。
【解决方案5】:

我认为不要再认为模型应该只是逻辑和数据库之间的层,这一点很重要。模型可以与数据库和其他模型一起使用,所有逻辑都应该在模型中。
我认为有两种方法:

  1. 您的模型可以在getContributors() 方法中返回 ID 数组,并且您可以创建新对象(可能是工厂),它将这些 ID 转换为对象。
  2. 您的模型可以返回对象数组,但不使用 new 关键字,而是通过工厂或依赖项容器(我更喜欢 DC)。

【讨论】:

  • 你现在在哪里看到模型?!?这里没有人认为模型是逻辑和数据库之间的层。有些人只是想把逻辑和sql放在一个地方,因此是activerecord(反)模式。
  • @tereško,让逻辑和 sql 在一个地方 - 没有错。不要那么紧张。
  • 这意味着,如果 DB 结构发生变化或类的逻辑发生变化,则该类将不得不更改 .. 从而破坏 SRP(这正是该主题的实际内容)。
  • DB是对象的数据存储的地方,所以DB结构应该反映它,只有在对象改变时才应该改变。
猜你喜欢
  • 2018-03-14
  • 1970-01-01
  • 1970-01-01
  • 2013-03-16
  • 1970-01-01
  • 2016-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多