【问题标题】:Implementing Domain Model and Data Mapper pattern with external data sources使用外部数据源实现域模型和数据映射器模式
【发布时间】:2012-08-14 10:58:58
【问题描述】:

更新:

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

控制器

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. 我需要引入一个缓存层,因为从外部数据库检索数据并不快。引入缓存层的最佳地点/实践在哪里?一种方法是在控制器中,因此将缓存层代码作为另一个映射器,如果这个缓存映射器不返回数据,我们可以走很长的路从外部检索东西。但是这个解决方案意味着我需要将所有这些逻辑都放在控制器动作中,也许有更好的方法来放置缓存层?

最初的问题:

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

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

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

    1. 用户
    2. SOAPBuilder
    3. RESTBuilder
    4. 用户SOAP
    5. 用户休息

现在我不喜欢这个设计的是,结构有点复杂,我不知道根据它们的“类型”(用户模型本身,构建器模型等)。

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

【问题讨论】:

  • 你应该始终支持组合而不是继承。

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


【解决方案1】:

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

也就是说,你看错了。您目前拥有的是active record 模式的变体。只是,在这种情况下,存储介质不是数据库,而是 REST API 和/或 SOAP 接口,而不是经典的 SQL 存储。

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

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

【讨论】:

  • 感谢 tereško 的回答。如果我理解正确,您建议将域对象(用户)传递给映射器(UserSOAP、UserREST),并让映射器根据请求操作/更新域对象。 (我的是将映射器封装到域对象中)我的问题是有什么好处?在我看来,这并没有真正改变大部分代码的去向,也没有真正改变复杂性。
  • @Vincent ,主要的好处是你获得了单独测试这一切的能力。此外,通过这种方式,您可以清楚地了解添加缓存系统。这样,如果您有一个可以从 SOAP 保存和检索数据的映射器和一个可以从 REST 保存和检索数据的映射器,那么您设计的系统可以从 REST 检索并在 SOAP 中保存。你会发现一个非常简单的 API 示例here。整个事情都与SRP联系在一起。
  • 显示一些代码可能会带来更好的答案。到目前为止,我一直在猜测您实际上隐藏在误用的流行词“模型”下的架构。
  • 如前所述,我们仍处于规划阶段,否则很乐意向您展示一些代码。事实上,我们还没有选择框架。为了保护被滥用的 MVC(我可能会因此而被钉死在十字架上,但 WTH),Web MVC 与其原始结构有很大不同,并且根据框架,解释和实现都是不同的。其中很多(如果不是大多数的话?)采用过于简单的“模型=数据库表”概念。我认为不考虑开发人员试图解决的问题,但批评设计并不总是有建设性的......
  • @Vincent ,您可能会发现 this answer 是有关 Web MVC 主题的有趣读物。
猜你喜欢
  • 2013-02-11
  • 2012-01-08
  • 2015-11-12
  • 2010-09-17
  • 2011-10-14
  • 1970-01-01
  • 2013-11-07
  • 1970-01-01
  • 2011-04-13
相关资源
最近更新 更多