钩子或事件以减少包之间的耦合

Hooks or Events to reduce coupling between packages

减少模块之间耦合的最佳方法是什么?

例如,如果我有一个 Invoice 包并且它与 Customer 包相关。

我的理解是,我必须使用“挂钩”系统来注入,例如,在客户的编辑视图中包含客户发票列表的选项卡。

反过来,使用事件系统从“发票”包的角度了解,例如,何时有人试图删除客户端。

我想实现的是降低耦合度,这样如果我删除发票包,客户端包不受影响。

我怎样才能得到它?使用 Laravel 的事件系统?使用像下面这样的自定义 class?

我的 Hooks class:

class HookRepository
{
/**
 * The repository items.
 *
 * @var \Illuminate\Support\Collection
 */
protected $items;

/**
 * Create a new repository instance.
 *
 * @return void
 */
public function __construct()
{
    $this->items = collect();
}

/**
 * Dynamically call methods.
 *
 * @param  string  $method
 * @param  array  $arguments
 * @return mixed
 */
public function __call(string $method, array $arguments)
{
    return $this->items->{$method}(...$arguments);
}

/**
 * Register a new hook callback.
 *
 * @param  string|array  $hook
 * @param  callable  $callback
 * @param  int  $priority
 * @return void
 */
public function register($hook, callable $callback, int $priority = 10): void
{
    $this->items->push(compact('hook', 'callback', 'priority'));
}

/**
 * Apply the callbacks on the given hook and value.
 *
 * @param  string  $hook
 * @param  array  $arguments
 * @return mixed
 */
public function apply(string $hook, ...$arguments)
{
    return $this->items->filter(function ($filter) use ($hook) {
        return !! array_filter((array) $filter['hook'], function ($item) use ($hook) {
            return Str::is($item, $hook);
        });
    })->sortBy('priority')->reduce(function ($value, $filter) use ($arguments) {
        return call_user_func_array($filter['callback'], [$value] + $arguments);
    }, $arguments[0] ?? null);
}
}

使用接口和抽象类实现Open/Close原理来自SOLID

  1. 确定接口。 ClassA 想从 ClassB 得到什么
  2. 概括 - 当您有一个接口时,您将能够识别大多数 类 需要实现它的常用操作。 (不要在这里尝试 future-proof 太多,否则很可能适得其反)

注意:如果您这样做是希望避免重构您的代码。算了吧。 :) 它只会让事情变得更容易,这已经是一个巨大的好处。

避免使用钩子来实现结构and/or行为模式。

编辑> Package 和 Hook 都不是 Laravel 或设计模式行话的一部分。

这本身应该给你一个提示。

让我来猜一猜:

    <?php
    PackageInterface {
        public function enable();
        public function disable();
        public function isEnabled();
        public function getHooks(): HookInterface[];
    }
    HookInterface {
        public function injectView();
        // or maybe
        public function injectIntoView($view);
    }

这完全取决于您何时加载包并将某些内容注入视图。

例如,当 $invoice->wasPaid() 或客户自己启用包时 enable()$customer->enable($package)