0

关注点分离或单一责任原则

“可能已经有你的答案”的问题下拉列表中的大多数问题仅解释“理论”,而不是回答我的简单问题的具体示例。

我想要完成的事情

我有一个名为 GuestbookEntry 的类,它映射到名为“guestbook”的数据库表中的属性。很简单!

最初,我有一个名为 getActiveEntries() 的静态方法,它检索在数据库中有条目的所有 GuestbookEntry 对象的数组。然后在学习如何正确设计 php 类的同时,我学到了两件事:

  1. 静态方法是不可取的。
  2. 关注点分离

我的问题:

处理关注点分离,如果 GuestbookEntry 类应该只负责管理单个留言簿条目,那么这个 getActiveEntries() 方法应该去哪里?我想学习绝对正确的方法来做到这一点。

4

3 回答 3

1

我想这个问题实际上有两个项目:

  1. 正如@duskwuff 指出的那样,静态方法本身并没有错。如果您知道它们的警告(例如“ Late Static Binding ”)和限制,它们只是另一个可以使用的工具。但是,对与 DB 的交互进行建模的方式确实会影响关注点分离,例如单元测试。

  2. 由于不同的原因,没有“绝对正确的方法”来做持久性。原因之一是每种解决方法都有不同的权衡。哪个更适合您的项目很难说。另一个重要的原因是语言不断发展,因此新的语言特性可以改进框架处理事物的方式。因此,与其寻找完美的方法,不如考虑使用关系数据库来实现 OO 持久性的不同方法:

    • 使用活动记录模式。到目前为止,您所做的看起来像是 Active Record 样式,因此您可能会觉得它很自然。活动记录的优点是易于掌握,但往往与数据库紧密耦合(当然这取决于实现)。从关注点分离的角度来看,这很糟糕,并且可能会使测试复杂化。
    • 使用 ORM(如DoctrinePropel)。在这种情况下,大部分繁重的工作都由框架完成(BD 映射、外键、级联删除、一些标准查询等),但您必须适应框架规则(例如,我记得在使用Doctrine 1 在项目中处理层次结构的方式。AFAIK 这些事情在 Doctrine 2 中得到了解决)。
    • 推出您自己的框架以适应您的项目需求和您的编程风格。这显然是一项耗时的任务,但你会学到很多东西。

作为一般的经验法则,我尽量让我的领域模型独立于 DB 之类的东西,主要是因为单元测试。单元测试应该在您编程时一直运行,因此它们应该运行得很快(我在编程时总是保持终端打开,并且在应用更改后我不断切换到它以运行整个套件)。如果您必须与数据库交互,那么您的测试将会变慢(任何中型系统都会有 100 或 200 个测试方法,因此这些方法应该以毫秒为单位运行才能有用)。

最后,有不同的技术来处理与 DB 通信的对象(例如模拟对象),但一个好的建议是始终在您的域模型和 DB 之间留一个层。这将使您的模型对更改更加灵活并且更易于测试。

编辑:我忘了提到DAO方法,也在@MikeSW 回答中说明。

高温高压

于 2012-10-31T14:13:01.163 回答
0

GetActiveEntries 应该是一个存储库/DAO 的方法,它将返回一个 GuestBookEntry 数组。该存储库当然可以实现一个接口,因此在这里您可以轻松进行测试。

我不同意为此使用静态方法,因为这显然是一个持久性访问问题。GuestBookEntry 应该只关心“业务”功能,而不关心数据库。这就是为什么使用存储库很有用,该对象将把业务层连接到数据库层。

编辑我的 php 生锈,但你明白了。

public interface IRetrieveEntries
{
    function GetActiveEntries();
}

public class EntriesRepository implements IRetrieveEntries
{
    private $_db;
    function __constructor($db)
    {
       $this->_db=$db;
     }

    function GetActiveEntries()
    {
      /* use $db to retreive the actual entries
       You can use an ORM, PDO whatever you want 
         */
      //return entries;
    }

  }

您将在需要访问功能的任何地方传递接口,即您不会将代码耦合到实际存储库。您还将使用它进行单元测试。关键是您将真正的数据访问封装在 GetActiveEntries 方法中,应用程序的其余部分将不知道数据库。

关于存储库模式,您可以阅读我写的一些教程(忽略使用的 C#,这些概念在任何语言中都有效)

于 2012-10-31T08:21:17.513 回答
0

不要再猜测自己了。静态方法getActiveEntries()是解决此问题的完全合理的方法。

您正在寻找的“企业”解决方案可能涉及创建 GuestbookEntryFactory 对象、将其配置为获取活动条目并执行它。这很愚蠢。静态方法是一种工具,这对他们来说是完全合适的工作。

于 2012-10-31T04:44:48.467 回答