1 Востаннє редагувалося ostap34PHP (09.08.2020 18:45:13)

Тема: [ООП] Куди інкапсулювати ініціалізацію класу на основі іншого класу?

Вітаю/Привіт/Добрий вечір.

Ситуація:

Є клас "Integration"
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

final class Integration extends Model
{
    protected $fillable = [
        'user_id',
        ...
        'sheet_file_id',
        ...
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
Є клас сповіщень
namespace App\Domain\Google;

use Closure;
use Illuminate\Support\Facades\Http;

class PushNotifications
{
    public string $channelId;

    public string $fileId;

    public string $token;

    public function __construct(string $channelId, string $fileId, string $token)
    {
        $this->channelId = $channelId;
        $this->fileId = $fileId;
        $this->token = $token;
    }

    public function subscribe(): array
    {
        return $this->request(function ($client) {
            return $client->post("https://www.googleapis.com/drive/v3/files/{$this->fileId}/watch", [
                'id'      => $this->channelId,
                'type'    => 'web_hook',
                'address' => route('webhook'), // todo
                'expire'  => 86400, // time in seconds = 1 day
            ]);
        });
    }

    public function unsubscribe(): array
    {
        return $this->request(function ($client) {
            $client->post("https://www.googleapis.com/drive/v3/channels/stop", [
                'id'          => $this->channelId,
                'resource_id' => $this->fileId,
            ]);
        });
    }

    private function request(Closure $closure)
    {
        $client = Http::withHeaders([
            'Authorization' => "Bearer {$this->token}",
        ]);

        $response = $closure($client);

        if ($response->clientError()) {
            throw new \Exception($response->json()['error']['message']);
        }

        return $response->json();
    }
}

Ці класи пов'язані. Тому що дані з першого передаються в другий.

Це відбувається таким чином:

new PushNotifications($integration->id, $integration->sheet_file_id, $integration->user->token->access_token)

Але повторювати цей уривок коду декілька раз виглядає як невиконання принципу DRY.

Питання:

Куди можна інкапсулювати цю ініціалізацію класу на основі іншого класу?

Деякі варіанти: (можливо є інші - кращі?)

  • В клас Integration

    Додати метод notifications який повертає клас сповіщень

        public function notifications()
        {
            return new PushNotifications($this->id, $this->.........);
        }

    Але здається це не відповідає принципу єдиного обов'язку - тому не впевенений чи це хороший спосіб.

  • Патерн "Проста фабрика"
    final class PushNotificationsFactory
    {
        public static function makeFromIntegration(Integration $integration): PushNotifications
        {
            return new PushNotifications($integration->id, $integration->........);
        }
    }
Подякували: koala, 0xDADA11C72

2

Re: [ООП] Куди інкапсулювати ініціалізацію класу на основі іншого класу?

Ну так ви ж самі собі відповіли - якщо дотримуватися SOLID, то потрібна окрема фабрика.

Подякували: ostap34PHP1

3

Re: [ООП] Куди інкапсулювати ініціалізацію класу на основі іншого класу?

@koala Дякую. (Були сумніви, тепер нема)