【问题标题】:Using adapter pattern when consuming 3rd party APIs and creating a domain in Laravel在使用 3rd 方 API 并在 Laravel 中创建域时使用适配器模式
【发布时间】:2019-04-26 13:18:10
【问题描述】:

在我的 Laravel REST API 项目中,我主要使用 3rd 方 API。为此,我有一个按 API(Accommodation、Planning、Discount 等)分组的“Services”文件夹,用于向 API 发送正确的参数并获取原始数据。

感觉这里需要使用适配器模式,因为这个第3方输出需要格式化。

让我试着举个例子。

我有一个 EventDao 接口(数据访问对象)和一个或多个具体的 EventDao 类,例如 EventbriteDao。

我还为每个具体的 DAO 提供了一个适配器。例如:EvenbriteAdapter

我将在某处拥有一些业务逻辑,因此我需要一个 Event entity 类。要将适配器的数据传递给实体,我需要一个 EventDTO 类(数据传输对象

我终于可以调用 eventDao(通过接口感谢 Laravel 的服务提供者)

我将其原始输出传递给适配器,然后将适配器的输出传递给实体。然后我可以调用实体类的方法之一。 (之后我需要将其转换为适当的 json 数据,但这是简单的部分。)

我不知道在哪里放置其他 CRUD 逻辑,如 updateEvent、deleteEvent、getAll 等。我应该直接在控制器中调用它们还是创建存储库(存储库模式 )?我对此感到困惑。

这是一种好方法还是过度设计?因为除了控制器之外,我还有 5-6 个类/接口。

另一个问题是直接在控制器中调用 EventbriteAdapter。我应该有一个接口吗?在这种情况下,我需要将服务和适配器接口都绑定到其在 AppServiceProvider 中的实现。

我的另一个问题是实体块的集合。如果我调用 getAll() 方法,我可以遍历数据并创建一个对象数组,但我对此并不满意。 Laravel 的集合会很有用,但我想将应用层与域分开。有什么好的解决方案?

这里我提到的一些文件的示例代码是:

interface EventAdapter
{
    public function getId();
    public function getName();
    public function getStartDate();
    public function getLocationName();
}



class EventbriteAdapter implements EventInterface
{
    private $raw;

    public function __construct(array $raw)
    {
        $this->raw = $raw;
    }

    public function getName()
    {
        return $this->raw['name'];
    }

    public function getStartDate()
    {
        return $this->raw['start'];
    }

    public function getLocation()
    {
        return $this->raw['venue']['name'].' '.$this->raw['venue']['address'];
    }
}


// Fetch event from Eventbrite (or other third-party)
$result = fetchEventFromEventbrite();

// Wrap event in adapter
$adapter = new EventbriteAdapter($result);

【问题讨论】:

  • 这个问题有很多内容,所以很难回答。当我处理更复杂的模式时,我经常参考这个文档,它可以帮助我做出决定:github.com/alexeymezenin/laravel-best-practices。希望它能给你一些方向:)。
  • 感谢@hdifen 的链接实际上这并不是 Laravel 特有的,但你是对的。关于同一个问题有很多事情。我希望我能挺过去。 :)

标签: laravel design-patterns architecture repository adapter


【解决方案1】:

我不知道在哪里放置其他 CRUD 逻辑,例如 updateEvent, deleteEvent、getAll 等。我应该直接在控制器中调用它们还是 创建存储库(存储库模式)?我对此感到困惑。

您可以使用the Gateway pattern 封装与第 3 方 API 交互的所有逻辑。网关可以包含获取数据和保存数据的方法。例如:

interface EventGatewayInterface
{
    /**
     * Get an event by id
     * 
     * @param mixed $id unique identifier of an event
     * @return Event the event
     */
    public function getById($id);

    /**
     * Get all events
     *
     * @return Event[] list of events
     */
    public function getAll();

    /** 
     * Add an event
     *
     * @param Event $event the event which will be added
     */
    public function add(Event $event);

    /**
     * Update an event
     *
     * @param Event $event the event which will be updated  
     */
    public function update(Event $event);

    /**
     * Delete an event
     *
     * @param Event $event the event which will be removed
     */
    public function delete();
}

这是一种好方法还是过度设计?因为我有5-6 控制器以外的类/接口。

实际上,您使用the Adapter pattern 将一种表示(原始表示)转换为另一种(对象表示)。但是适配器模式用于将一个程序接口转换为兼容的程序接口。转换使用the Mapper pattern 的表示。您可以实现简单的映射器,例如:

class RawEventMapper
{
    /**
     * Map raw data to an event object
     * 
     * @param array $data raw data
     * @return Event the event object
     */
    public function map(array $data)
    {
        $event = new Event();
        $event->name = $data['name'];
        $event->startDate = $data['start'];
        $event->location = $data['venue']['name'].' '.$data['venue']['address'];
        return $event;
    }
}

并在网关中使用它来将原始数据转换为对象。

class ConcreteEventGateway implement EventGatewayInterface
{
    /** @var RawEventMapper data mapper */
    protected $mapper;

    /**
     * Constructor
     *
     * @param RawEventMapper $mapper data mapper
     */ 
    public function __construct(RawEventMapper $mapper)
    {
        $this->mapper = $mapper;
    }

    /** @inheritdoc */
    public function getById($id)
    {
        // get raw data from 3rd party API
        return $this->mapper->map($raw);
    }
}

Laravel 的集合会很有用,但我想分开 来自域的应用层。有什么好的解决方案?

如果你的目标是创建一个独立于框架的领域层,你不应该使用 Laravel 集合。

【讨论】:

  • 非常感谢您的精彩解释。网关模式似乎最适合使用 3rd 方 API,但实际上我的数据访问对象几乎已经这样做了。可能只需要改名。我担心的是,RawEventMapper 依赖于第 3 方。每个服务可能有不同类型的输出。那么,我应该为每个服务创建具体的映射器类吗?还有一个映射器接口来使第 3 方服务可互换?听起来不错?而且我认为也可以在数据映射器中使用适配器类,但据我了解,这不是必须的。
  • @KorayKüpe 因为每个第 3 方 API 都有自己的输出,您应该为每个 API 创建 Mapper。映射器接口使转换不同的输出可互换,但没有第 3 方服务。使用 GatewayInterface 使第 3 方服务可互换
猜你喜欢
  • 1970-01-01
  • 2018-04-21
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 2016-09-14
  • 2020-04-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多