model-view-controller - 使用外部数据源实现域模型和数据映射器模式

标签 model-view-controller design-patterns frameworks datamapper domain-model

更新:

好的一些更新,最后我们决定了框架(Yii)并有一些初始结构。我将粘贴一些相关代码来说明我们当前的状态: (此处仅读取操作)

Controller

class SponsorController extends RestController
{
    public function actionRestView($id)
    {
        $sponsorMapper = new SponsorMapper(
            new Db1Adapter(), // Gateway to the external SOAP Webservice
            new Db2Adapter()  // Gateway to the external REST Webservice
        );

        $data = $sponsorMapper->read($id);

        $this->renderJson(
            array(
                'success' => true,
                'message' => 'Record Retrieved Successfully',
                'data' => $data
            )
        );
    }
}

领域模型

class Sponsor extends CModel
{
    public $id;
    public $db1Result;
    public $db2Result;

    public function attributeNames()
    {
        return array(
            'id',
            'db1Result',
            'db2Result',
        );
    }
}

数据映射器

class SponsorMapper extends Mapper
{
    public function __construct(SoapAdapter $db1Adapter,
                                RestAdapter $db2Adapter)
    {
        $this->adapters['soap'] = $db1Adapter;
        $this->adapters['rest'] = $db2Adapter;
    }

    public function read($id)
    {
        $db1Result = $this->adapters['soap']->demoRequest();
        $db2Result = $this->adapters['rest']->demoRequest();

        return $this->createEntity($db1Result, $db2Result);
    }

    protected function createEntity($db1Result, $db2Result)
    {
        $sponsor = new Sponsor();
        $sponsor->db1Result = $db1Result;
        $sponsor->db2Result = $db2Result;

        return $sponsor;
    }
}

现在我有两个问题:

  1. 现在 Sponsor 对象的属性只是 db1Result 和 db2Result,我将其更改为实际属性(例如,firstName、lastName、email),因此 SponsorMapper::createEntity 将如下所示:

    protected function createEntity($db1Result, $db2Result)
    {
        $sponsor = new Sponsor();
        $sponsor->firstName = $db1Result->result->first_name;
        $sponsor->lastName = $db1Result->result->last_name;
        $sponsor->email = $db2Result->QueryResult->ItemObject->email;
    
        return $sponsor;
    }
    

在我看来,这些事情应该发生在域对象而不是映射器内部;我知道我可以将 db1Result 和 db2Result 视为它们自己的域对象,并创建它们与 Sponsor 域对象的关系,但我不确定这是否是正确的方向。我应该在映射器中执行此操作吗?

  1. 我需要引入一个缓存层,因为从外部数据库检索数据并不快。引入缓存层的最佳地点/实践在哪里?一种方法是在 Controller 中,因此将缓存层编码为另一个映射器,如果该缓存映射器不返回数据,我们就可以从外部检索数据。但这个解决方案意味着我需要将所有这些逻辑放在 Controller 操作上,也许有更好的方法来放置缓存层?

初始问题:

我们正在 PHP MVC 框架之上设计/创建 RESTFul API 项目。该项目的目标是充当其他两个“外部”API(一个 SOAP,另一个 REST)之间的适配器。

我认为这个项目中的模型应该大致如下工作:

  • 假设我们在两个“外国”数据库上都有用户数据集合 在各自的 API 后面,我们在本地创建一个模型“User”
  • 假设我们在“User”模型中有一个“GetById”方法,它需要 to:通过 id 从两个外部 API 中获取用户数据,合并并 返回结果。
  • 我可能会在“用户”模型中使用构建器模式来 实例化 2 个其他模型(对于每个外部 API),并询问这 2 个模型 模型来获取数据。通过这个结构,我可以让 2 个额外的 模型继承事物需要他们与他们的沟通 API。
  • 所以我们有这些模型:

    1. 用户
    2. SOAPBuilder
    3. RESTBuilder
    4. 用户SOAP
    5. 用户REST

现在我不喜欢这个设计的是,结构有点复杂,我不知道有什么好方法可以根据这些模型文件的“类型”(用户模型本身,构建器模型等)。

我是不是设计过度了?我应该考虑更好的模式吗?

最佳答案

MVC 中没有“多个模型”。模型是构成 MVC 设计模式的两层(以及表示层)之一。人们通常所说的“模特”其实是domain objects 。您可能会发现this相关。

也就是说,您看待这件事的方式完全错误。您当前拥有的是 active record 的变体图案。只是,在本例中,存储介质不是数据库,而是 REST API 和/或 SOAP 接口(interface),而不是经典的 SQL 存储。

在这种情况下,最好的选择是将域对象(例如:User)与存储相关逻辑的不同元素分开。我个人更喜欢实现data mappers为了这。本质上,如果您有一个域对象,则将其传递给映射器的方法,然后该方法从所述对象检索信息并将其发送到存储,或者从存储检索数据并将其应用到该域对象。

User 实例不关心它是否保存。它对域逻辑没有影响。

关于model-view-controller - 使用外部数据源实现域模型和数据映射器模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12015202/

相关文章:

model-view-controller - 如何命名 Controller 和模型之间的层 codeigniter MVC

design-patterns - 什么是 Microsoft Unity?

c++ - 使用 Wt 框架监听数据

c# - 如何跟踪上次对DDD中的对象进行更改的用户?

Javascript 与 PHP——框架与库

ios - 是否可以使用 Storyboard开发 iOS 框架?

php - PHP 应用程序中分离用户界面和数据库开发

php - MVC 困惑;梳理模型职责和架构

asp.net-mvc - 如何在asp.net mvc 中创建一个弹出窗口?

c# - 装饰者模式与继承的例子