【问题标题】:What is a domain object and what is its purpose?什么是域对象,它的用途是什么?
【发布时间】:2014-06-30 08:58:57
【问题描述】:

我最近开始学习 OOP 和 MVC,但我已经遇到了很多问题! :)

我想澄清一下这个网站上的名单http://c2.com/cgi/wiki?DomainObject

  1. 识别 [of their] 哪些引用表示聚合,哪些表示关联
  2. 复制自己
  3. 维护业务逻辑
  4. 将自己与其他同类型的域对象进行比较
  5. 方便选择打印或显示它们的其他对象
  6. 对其域信息进行测试”
  7. 表明自己的身份
  8. 验证自己

1:它们是指返回其他域对象 ID 的方法列表吗?

7 & 8:“识别和验证自己”是什么意思?这应该如何工作,因为识别和验证可能需要访问持久层?

在过去的几个月里我读了很多书,但实际上我不能说我对 OOP/MVC 有一个扎实的想法:(

什么是验证?为什么我需要它?它应该如何执行?如果数据来自数据库,为什么我需要验证,因为持久数据已经有效?

凭借我自己的洞察力,我为我拥有的每个模型实体组成了这组类:

// it holds Student information, it can also contain partial data
// (for updating just certain fields in the database)
interface Student
{
    getID($id)
    setID($id)
    getName()
    setName($name)
    getSurname()
    setSurname($surname)
}

interface StudentValidator
{
    validateInsert(Student $data)
    validateDelete(Student $data)
    validateUpdate(Student $data)
}

interface StudentMapper
{
    getByID($id)
    getAllByClassroomID($crid)
    updateByID(StudentValidator $v, int $id, Student $data)
    deleteByID(StudentValidator $v, int $id)
    deleteAllByClassroomID(StudentValidator $v, int $crid)
    insert(StudentValidator $v, Student $data)
}

这离体面的代码还有多远? :)

提前谢谢!!!

【问题讨论】:

    标签: php oop model-view-controller


    【解决方案1】:

    验证和东西

    域对象内的验证将仅限于它所包含的业务规则。例如,当调用$student->isValid() 时,域对象会看到,如果名称和姓氏已设置,以及它们是否在奇怪的地方不包含数字(例如,“弗雷德里克威廉三世”完全有效,但不太可能,名称) .

    这不包括数据完整性检查(例如检查学生的电子邮件地址是否尚未注册,从而违反UNIQUE 约束)。数据完整性由映射器验证。如果您使用 PDO 进行持久性抽象,那么在完整性错误的情况下,它将引发异常,您可以在映射器内部处理该异常,并在您尝试存储的域对象上设置错误状态。

    自我识别

    “认同自己”的描述有点模糊。我假设它会引用比较对象这样的操作(例如:$studentA === $studentB 来验证它是否是同一个学生)。

    参照物

    识别哪些 [of their] 引用表示聚合,哪些表示关联

    这一点讨论域对象之间的交互。就像调用$course->addStudent($student); 一样,它将定义Course 和Student 实例之间的某种关系。我对 UML 方面有点生疏,但我认为这表明:

    • 课程包含学生集合
    • 学生与课程相关联

    一个简化的和有点笨拙的例子,它说明了你遇到的所有问题可能看起来像这样:

    $student = new Student;
    $studentMapper = new StudentMapper($pdo);
    
    $student->setId(42);
    
    if (!$studentMapper->fetch($student)) { 
       // error , missing student
       return;
    }
    
    // found the one with ID 42
    $course = new Course;
    $courseMapper = new CourseMapper($pdo);
    
    $course->setId(31);
    
    if (!courseMapper->fetch($course)) {
       // missing course
       return;
    }
    
    $course->addStudent($student);
    
    if ($course->isValid() && $student->isValid()) {
       // check if there are free spots in course 
       // and student has prerequisites
       $courseMapper->store($course);
       $studentMapper->store($student);
    }
    

    当映射器尝试存储数据时,检查是否存在课程-学生双重预订。

    注意:您可能还会注意到,这开始有点像交易案例的味道。这就是为什么在大规模 OOP 代码库中通常使用 Units of Work 的原因之一。

    注意 nr.2: 请记住,“域对象”和“域对象集合”是两个不同的东西。这些实体的持久性也是如此。有点像this 旧帖子中所述。

    【讨论】:

    • 感谢您的回答!!在不同的班级进行验证不是更好吗?我可以在不同的域对象实现上重用它。无关,我喜欢 $mapper->fetchInto($obj)... 我只是想知道如何在从映射器获取实例的同时任意切换类名!我目前正在使用 $obj->fetch($className),但您的建议肯定更好(如果我理解正确的话 ^_^)。关于这一点,如何使用集合来做到这一点? $studentMapper->fetchAll(new Student()) 并在内部使用“克隆”怎么样?
    • 没关系,没有克隆的东西会是 fetchAll(new StudentCollection()) !对吗?
    • 让我们看看我是否理解你。在实践中,验证规则很少重复。当他们这样做时,无论如何,这大部分是你应该用Filter API 做的事情。另外,我注意到,验证者在实践中存在无法控制的增长趋势。
    • 这个例子是“简化的”。实际上,您不会在服务层代码的任何地方看到$student = new Student。相反,您可能会使用工厂。这意味着同一行看起来像$student = $this->domainFactory->create('Student');,它还会为您提供“压力点”,您可以在其中决定是否必须返回Student、Padawan 或TestingBrick 的实例。只要它们实现相同的接口,映射器也应该能够填充和持久化这些实例。创建映射器也是如此。
    • 是的,我认为您理解我的正确。问题$obj->fetch($className) 方法(不幸的是它非常流行)是你最终得到了映射器类也有工厂的职责。这显然会违反SRP 而不会获得任何实际利益。这也剥夺了您在单个对象上按顺序使用多个映射器的能力。例如$user = new User; $session->fetch($user); $sql->fetch($user) 填充当前登录的用户。
    猜你喜欢
    • 1970-01-01
    • 2010-09-27
    • 2011-12-17
    • 2010-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多