保持MVC模型与数据库松散耦合?


9

我喜欢保持我的代码可测试性,并决定对我当前的MVC框架采用依赖注入策略,这无疑已被证明是确保松散耦合的代码,可测试性和模块化的好方法。

但是,由于与设计模式的掌握程度相去甚远,因此我很难找到一种使模型尽可能与数据库连接器类保持松散耦合的好方法。

这怎么办?
由于我没有随此问题提供任何物理代码,因此,我将不胜感激一些逻辑/代码示例或信息,这些示例或信息可为我提供一个理解上述问题的方向。


这个问题属于软件工程,因为它更多地是关于这个主题的结构和思考,而不是关于在代码中实现它。
Lasse V. Karlsen

Answers:


6

一种方法是在设计数据库之前先设计模型。设计模型时,重点是捕获问题域中的业务逻辑和含义。这应该以一种对业务有意义的方式来捕获,不仅包括实体和数据字段。有些数据元素是从其他数据元素解释而来的,有些则取决于其他条件,等等。此外,您还将向模型添加所需的任何基本逻辑,例如,将某个元素设置为某个值时,对象内部的响应方式。

您最终很可能会获得与持久存储数据相同90%以上的一致性。没关系。它可以完全相同而无需耦合。

还要注意,在真正的持久性无知的迷雾中对域进行建模对于软件设计来说是一个圣杯。如果可以做到,那就太好了。但是,如果问题域非常重要且具有复杂性,那么不时退出域建模还是一个好主意,以便对数据持久性进行完整性检查以确保您没有绘制陷入困境

只需记住各个组件的实际角色,并在设计它们时将它们分开即可。对于任何给定的设计决策,请问自己是否违反了以下任何角色:

  1. 数据库-存储数据,维护数据完整性,保持数据静止。
  2. 模型-包含业务逻辑,对问题域进行建模,保持数据运动,响应业务级事件等。
  3. 视图-将数据呈现给用户,执行用户端逻辑(在模型中执行真实验证之前进行基本验证,等等)。
  4. 控制器-响应用户事件,将控制权传递给模型,路由请求并返回响应。

嗨,大卫。感谢您的广泛答复!在保持高水平的松散耦合的同时,如何将模型与数据库连接器连接?
工业

1
@Industrial:有很多方法可以将模型连接到持久性,但是到目前为止,我发现真正能够满足我分离关注点的唯一方法是在域中具有由DAL外部实现的存储库接口。存储库方法接受并返回域模型,并在内部模型和任何生成的数据库实体之间进行内部转换。(老实说,我在PHP中没有做太多事情。)因此,您可以使用DAL框架自动生成所有DB CRUD等,然后将存储库编写为该库和模型之间的接口。
大卫,

@Industrial:例如,如果您使用ORM,则该ORM将由您的DAL(与领域模型隔离)引用,并将其相应地转换为数据访问模型。或者,如果您使用手动SQL进行直接数据库访问,则可以在DAL的存储库方法中进行操作,然后将SQL查询的结果转换为域模型,然后再返回它们。
大卫,

@Industrial:还请记住,存储库方法不必只是CRUD。该代码中可以包含很多智能。许多更复杂的代码可以具有许多内部代码,这些内部代码可以转换数据库中的数据。或者,如果复杂的过程涉及到数据库的多次旅行,那么为了提高性能,您可以将逻辑放入存储过程中,而DAL方法只是传递给该过程并将结果转换为模型。
大卫,

嗨,大卫!只是想再次感谢您的回答。绝对是我在StackExchange上收到的最好的软件之一!
工业

2

您想拥有两件事。

  1. 您的模型(DBAL的访问者,并执行大多数应用程序逻辑)。
  2. 您的“域模型”又称为数据实体,它们代表系统的实体,例如用户,帖子,产品等。

    class PPI_Model_User {
    
        protected $_conn = null;
    
        function __construct(array $options = array()) {
            if(isset($options['dsnData'])) {
                $this->_conn = new PPI_DataSource_PDO($options['dsnData']);
            }
        }
    
        function getAll() {
            $rows = $this->_connect->query("SELECT .....")->fetchAll();
            $users = array();
            foreach($rows as $row) {
                $users[] = new PPI_Entity_User($row);
            }
            return $users;
        }
    
    }

使用代码

    $model = new PPI_Model_User(array('dsnData' => $dsnData));
    $users = $model->getAll();
    foreach($users as $user) {
        echo $user->getFirstName();
    }

在那里,您就可以创建域模型(实体),并使MVC模型执行数据库连接和数据操作。

如果您想知道什么是PPI,请使用Google搜索“ PPI框架”。

祝您搜索顺利。

此致,保罗·德拉贡尼斯(Paul Dragoonis)。


1

记住,MVC是在Smalltalk中出现的,它具有对所有对象的自动持久性。因此,MVC模式没有为模型/持久性分离规定任何解决方案。

我的喜好是提供一个“存储库”对象,该对象知道如何从数据库创建模型对象并将模型对象存储到数据库。然后,模型对持久性一无所知。但是,某些用户操作将不得不触发保存,因此Controller可能会知道存储库。我通常使用某种形式的依赖注入,以防止将控制器耦合到存储库。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.