观察到的在MVC模型相互依存的执行树(On observing an execution tree

2019-08-03 01:33发布

我已经有一段时间了(4个月)在Yii框架开发的,到目前为止,我还遇到了一些问题,MVC,我要在那里与有经验的开发人员共享。 我将列出他们的复杂程度存在这些问题。

[第1级] CR(创建更新的)形式 。 首先,我们有很多的形式。 每个表单本身就是一个模型,所以每个人都有一些验证规则,一些属性,以及一些操作上的属性进行。 在很多情况下,每一种形式都做更新和使用一个单一的活动记录的对象在数据库中创建记录。
- >因此,在这种复杂的,形式有

  • 打开时,

    • 能够以人性化的方式来显示从DB数据库友好的数据

    • 能够显示所有与有源记录对象的属性表单字段。 添加,删除,从db表改变列具有影响的形式的显示。

  • 节省的情况下能够获得数据之前格式化人性化的数据到数据库友好的数据

  • 时验证,能够执行由活动记录对象执行基本的验证,还必须执行其他验证完成一些业务规则

  • 验证失败时,可以回滚到属性进行了以及对数据库做出的变更,并展示他们的最初输入数据的用户。

[2级] 扩展CR形式 。 可在执行一次从不同的表中的记录创建/更新的形式。 不仅如此,形式是否会造成其记录有时取决于其他条件(多个业务规则 )一/更新,这样一种形式有时可以在表A中更新记录,B而不是d,有时在一个更新记录,d而非B - >因此,在这种复杂的,我们看到了一个表格,以:

  • 能够满足[1级]

  • 能够有条件创建的某些记录/更新,有条件创建的某些记录某些列/更新。

[第3级] 模型的树 。 窗体的应用程序中的作用是,在很多方面,可以让用户的交互与应用程序的端口。 为了满足请求,该端口将与许多其他对象,反过来,许多多个物体进行交互交互。 一些对象可以被看作是模型。 活动记录是一个模型,但梅勒也可以是一个模式,所以是一个RobotArm。 这些模型使用彼此以满足用户的要求。 每个型号都执行自己的操作,整个树必须能够回滚错误/失败的情况下所做的任何更改。

有没有人在那里遇到或能解决这些问题呢?

我想出了很多东西像的ModelAttribute对象封装模型的属性,以解决整个客户端,服务器和DB层的存在。

我也认为我们应该给的模型树观察者进行观察,并通知观察模型发生错误时回滚的变化。 但是,如果能有什么多个观察者,如果一个节点使用什么其父的观察员,但给它的孩子另一个观察员。

工程师,开发商,Rails的,Yii的,Zend公司,ASP,JavaEE的,任何人MVC,请加入为科学而本次讨论。

- 更新到teresko的回应:---
@teresko其实我打算将服务纳入工作单元内执行,并有工作的单位不担心新的/更新/删除。 工作单位内的每个对象将负责它的状态和需要实现自己的承诺()和rollback()。 一旦错误发生,工作单元将回滚从最新注册的对象的最早注册的对象的所有的变化,因为我们不仅处理数据库,如果不是的话,树成功执行我们可以邮寄,出版社等。 ,我们称之为从最早注册的对象到最新注册的对象的commit()。 通过这种方式,邮件可以保存邮件和发送上提交。

使用数据映射器是一个伟大的想法,但我们仍然必须确保列在数据库中的数据映射器和域对象相匹配。 此外,一个扩展CR形式或具有取决于其他模型的属性必须在验证和数据类型方面匹配它们的属性的模型。 因此,也许一个属性可以是对象和模型运到模型? 一个属性也可以告诉它是否被修改过,应该对其执行什么验证,以及它如何能够人性化,应用型,和db友好。 任何更新到DB模式将影响该属性,并由此引发,需要开发人员可以更改系统来满足这种变化异常。

Answer 1:

原因

你的问题的根源是滥用活动记录模式。 AR是为只有基本的CRUD操作简单域实体。 当你开始添加大量的验证逻辑的和多个表之间的关系,该模式开始破裂。

活动记录,在其最好的,是一个小SRP违规行为,为简单起见。 当你开始打桩更多的责任,你开始招致严厉的处罚。

解决方案(S)

1级:

最好的选择是独立的业务和存储逻辑。 它经常用做域对象和数据映射器 :

  • 域对象 (在其他材料也被称为业务对象或领域模型对象)处理验证和具体的业务规则,是完全不知道的,如何(甚至是“如果”)在其数据存储和检索。 他们还让你拥有不直接绑定到一个存储结构(如数据库表)对象。

    例如:你可能有一个LiveReport域对象,它代表了最新的销售数据。 但它可能没有具体的表DB。 相反,它可以通过几个映射器进行维修,从内存缓存,SQL数据库和一些外部SOAP该池的数据。 而LiveReport实例的逻辑是完全无关的存储。

  • 数据映射器知道在哪里把从域对象的信息,但他们没有任何验证或数据完整性检查。 认为他们可以能够处理从低级别的存储抽象锥,像违反例外UNIQUE约束。

    数据映射器还可以进行交易,但是,如果一个事务需要多个领域对象要执行,你应该寻找增加工作单位(更多关于它更低)。

    在更先进的/复杂的情况下,数据映射器可以交互和使用的DAO和查询建设者。 但是,这更多的情况,当你的目标是创建一个ORM一样的功能。

    每个域对象可以有多个映射器,但每个映射只能与特定类别域对象的工作(或其中的一个子类,如果你的代码符合LSP )。 你也应该认识到,域对象和域对象的集合,是两个不同的东西,应该有独立的映射器。

    此外,每个域对象可以包含其它域对象,就像每个数据映射器可以包含其他映射器。 但是,在映射器的情况下,它是偏好的更是一个事(我不喜欢强烈)。

另一项改进,这可能缓解当前的混乱,将防止在表示层(最常见的 - 控制器)泄漏应用程序逻辑。 相反,你将在很大程度上从使用中获益的服务 ,包含映射器和域对象之间的交互,从而为您的模型层公共十岁上下的 API。

基本上,你封装模型的完整片段,可服务(在真实的世界 - 轻微的努力和调整),在不同的应用程序重复使用。 例如: RecognitionMailerDocumentLibrary将所有服务。

另外,我觉得我不应该,不是所有的服务都包含域对象和映射器。 一个比较好的例子就是前面提到的Mailer ,这可能是直接通过控制器通过另一服务使用,或者(更重要的是可能的)。

2级:

如果您停止使用活动记录模式,这变得相当简单的问题:你需要确保,你从这些领域对象,这实际上已经改变了自上次保存后只保存数据。

在我看来,有两种方式来处理这个:

  1. Quick'n'Dirty

    如果有什么改变,只是更新了一切...

    顺便说一句,我宁愿是引入checksum的域对象,从所有的域对象的变量持有的哈希(当然,用的异常变量checksum它的自我)。

    各映射器询问是否保存一个域对象时,它调用一个方法isDirty()此域对象,它会检查,如果数据已经改变。 然后映射器可以采取相应的行动。 这也与一些调整,可用于对象图(如果他们不广泛,在这种情况下,你可能需要无论如何重构)。

    另外,如果您的域对象实际上被映射到多张表(甚至是不同的形式储存的),它可能是合理的,有几个校验,每个组变量。 由于映射器已经为域对象的特定类别编写的,它不会加强现有的耦合。

    对于PHP,你会发现在一些代码示例这个ansewer 。

    注意:如果您的实现是使用DAO中来隔离数据映射器域对象,然后根据校验和验证的逻辑,将被移动到DAO。

  2. 工作单位

    这是“行业标准”的问题所在,并有一整章(11日)与它在处理POEAA书。

    其基本思路是这样的,你创建一个实例,其作用类似于控制器(古典,不是在这个词的MVC意义上的),你的域对象和数据映射器之间。

    每次修改或删除域对象时,就告知其工作的单位 。 每次在域对象加载数据的时候,你问工作单位来执行该任务。

    有两种方法来讲述变更工作单位

    • 呼叫者登记:执行所述变化对象还通知该工作单元
    • 对象注册:改变的对象(通常是从设定器)通知该工作单元,它被改变

    当所有域对象的交互已经完成,你可以调用commit()方法的工作单元。 然后,它认为必要的映射器和存储存储所有的改变域对象。

3级:

在这个阶段,复杂性的唯一可行的实现是使用工作单位。 这也将是负责启动和提交的SQL事务(如果使用的是SQL数据库),用适当的回滚条款。

PS

读的书“企业应用架构模式”。 这就是你迫切需要。 这也将纠正对MVC和MVC设计灵感patters的误解,你已经通过使用Rails样的框架收购。



文章来源: On observing an execution tree of interdependent models in MVC