Heim  >  Artikel  >  PHP-Framework  >  Laravel-Schnittstellenorientierte Programmierung (Praxis)

Laravel-Schnittstellenorientierte Programmierung (Praxis)

Guanhui
Guanhuinach vorne
2020-05-21 11:06:213467Durchsuche

Laravel-Schnittstellenorientierte Programmierung (Praxis)

Schnittstellenorientierte Programmierung ist eine Designphilosophie in der Codierung, die Anwendungen basierend auf Schnittstellen und nicht auf festen Klassen erstellt.

Wenn Sie Programmierer sind, haben Sie vielleicht schon von solchen Sprüchen gehört, wie zum Beispiel: schnittstellenorientierte Programmierung, Verwendung abstrakter Klassen anstelle fester Klassen usw.

Dies alles sagt dasselbe aus: Wenn Sie Anwendungscode schreiben, sollten Sie dafür sorgen, dass er sich auf abstrakte Schnittstellen und nicht auf konkrete Klassen verlässt.

Warum?

Das war genau meine Reaktion, als ich diesen Satz zum ersten Mal hörte. Warum Schnittstellen anstelle von Klassen verwenden? Selbst wenn die Schnittstelle erstellt wird, muss ich eine Klasse erstellen, die die Schnittstelle implementiert. Ist das nicht Zeitverschwendung?

Natürlich nicht! !

Die einzige Konstante auf dieser Welt ist die Veränderung selbst, das heißt, Veränderung ist ewig.

Was die Programmierung betrifft, gibt es hiervon keine Ausnahmen. Da sich die Geschäftsanforderungen im Laufe der Zeit ändern, muss sich auch unser Code ändern.

Der Code muss also flexibel bleiben.

Schnittstellenorientierte Programmierung kann den Code lose gekoppelt und flexibel machen.

Wie geht das?

Beachten Sie den folgenden Code.

class Logger {
    public function log($content) 
    {
        //日志保存到文件中.
        echo "Log to file";
    }
}

Dies ist eine einfache Klasse, die in einer Datei protokolliert. Wir können es im Controller aufrufen.

class LogController extends Controller
{
    public function log()
    {
        $logger = new Logger;
        $logger->log('Log this');
    }
}

Aber was sollen wir tun, wenn wir Protokolle an mehreren Orten aufzeichnen müssen (wie Datenbanken, Dateien, Clouds usw.).

Wir können dann die Klassen LogController und Logger ändern, um diese Änderungen zu berücksichtigen.

class Logger {
    public function logToDb($content) 
    {
        //将日志记录到 db.
    }
    public function logToFile($content) 
    {
        //将日志保存到 file.
    }
    public function logToCloud($content) 
    {
        //将日志存储到 cloud.
    }
}
rrree

Jetzt können wir verschiedene Ziele erfassen. Was aber, wenn wir dem Redis-Server weitere Ziele (z. B. Protokolle) hinzufügen möchten? Abschließend werden wir sowohl die Logger-Klasse als auch die LogController-Klasse ändern.

Wie Sie sehen, geriet dies schnell außer Kontrolle und der Code wurde unübersichtlich. Die Logger-Klasse wurde schnell zu einem Ganzen. Das ist ein Albtraum.

Also müssen wir die Dinge aufteilen. Gemäß den SOLID-Prinzipien können wir die Verantwortlichkeiten in die entsprechenden Klassen verschieben.

class LogController extends Controller
{
    public function log()
    {
        $logger = new Logger;
        $target = config('log.target');
        if ($target == 'db') {
            $logger->logToDb($content);
        } elseif ($target == 'file') {
            $logger->logToFile($content);
        } else {
            $logger->logToCloud($content);
        }
    }
}

und der Controller wechselt zu:

class DBLogger
{
    public function log()
    {
        //将日志记录到 db
    }
}
class FileLogger
{
    public function log()
    {
        //将日志保存到 file
    }
}
class CloudLogger
{
    public function log()
    {
        //将日志存储到 cloud
    }
}

Das ist viel besser. Wenn wir nun zusätzliche Protokollierungsziele hinzufügen möchten, können wir eine neue Klasse erstellen und diese zum if-else im Controller hinzufügen.

Allerdings ist weiterhin unser Controller für die Auswahl des Loggers verantwortlich. Für den Controller ist es nicht erforderlich, die verschiedenen Logger zu kennen und zwischen ihnen zu wählen. Es ist lediglich eine Logger-Klasse mit einer log()-Methode erforderlich, um Inhalte zu protokollieren.

Schnittstellen verwenden

Diese Situation eignet sich für die Verwendung von Schnittstellen. Was ist also eine Schnittstelle?

Eine Schnittstelle ist eine Beschreibung der Operationen, die ein Objekt ausführen kann.

Für unser Beispiel benötigt der Controller nur die Logger-Klasse mit der log()-Methode. Daher muss unsere Schnittstelle beschreiben, dass sie über eine log()-Methode verfügen muss.

class LogController extends Controller
{
    public function log()
    {
        $target = config('log.target');
        if ($target == 'db') {
            (new DBLogger)->log($content);
        } elseif ($target == 'file') {
            (new FileLogger)->log($content);
        } else {
            (new CloudLogger)->log($content);
        }
    }
}

Wie Sie sehen, enthält es nur die Funktionsdeklaration und nicht deren Implementierung, deshalb wird es abstrakt genannt.

Bei der Implementierung einer Schnittstelle muss die Klasse, die die Schnittstelle implementiert, die Implementierungsdetails der in der Schnittstelle definierten abstrakten Methoden bereitstellen.

In unserem Beispiel muss jede Klasse, die die Logger-Schnittstelle implementiert, Implementierungsdetails der abstrakten Methode log() bereitstellen.

Wir können diese Schnittstelle dann in den Controller einbauen.

interface Logger
{
    public function log($content);
}

Jetzt kümmert sich der Controller nicht mehr um den ihm übergebenen Loggertyp. Es muss lediglich wissen, dass es die Logger-Schnittstelle implementieren muss.

Daher müssen wir die Logger-Klasse ändern, um diese Schnittstelle zu implementieren.

class LogController extends Controller
{
    public function log(Logger $logger)
    {
        $logger->log($content);
    }
}

Jetzt können wir weitere Logger hinzufügen, ohne den vorhandenen Code zu berühren. Wir müssen lediglich eine neue Klasse erstellen, die die Logger-Schnittstelle implementiert.

class DBLogger implements Logger
{
    public function log()
    {
        //将日志记录到 db
    }
}
class FileLogger implements Logger
{
    public function log()
    {
        //将日志存储到 file
    }
}
class CloudLogger implements Logger
{
    public function log()
    {
        //将日志保存到 cloud
    }
}

Unser Code sieht jetzt flexibel und niedrig gekoppelt aus. Wir können die Implementierung jederzeit ändern, ohne den vorherigen Code zu ändern.

Abhängigkeitsinjektion

Wenn wir das Laravel-Framework verwenden, können wir den Service-Container verwenden, um die Implementierung der Schnittstelle automatisch zu registrieren.

Da Laravel die Methodeninjektion sofort bereitstellt, müssen wir nur die Schnittstelle und die Implementierung binden.

Zuerst müssen wir eine Logger-Konfigurationsdatei erstellen. Einfach so

class RedisLogger implements Logger
{
    public function log()
    {
        //将日志存储到 redis
    }
}

Dann fügen Sie den folgenden Code zur Datei AppServiceProvider.php unter dem Pfad app/Providers hinzu

<?php
return [
    &#39;default&#39; => env(&#39;LOG_TARGET&#39;, &#39;file&#39;),
    &#39;file&#39; => [
        &#39;class&#39; => App\Log\FileLogger::class,
    ],
    &#39;db&#39; => [
        &#39;class&#39; => App\Log\DBLogger::class,
    ],
    &#39;redis&#39; => [
        &#39;class&#39; => App\Log\RedisLogger::class,
    ]
];

Dies bewirkt, dass der Standard-Logger aus der logger.php-Konfiguration gelesen wird Datei. Dann an die Logger-Schnittstelle binden. Wenn wir die Logger-Schnittstelle verwenden, analysiert der Container auf diese Weise die Standard-Logger-Instanz und gibt sie für uns zurück.

Da der Standard-Logger mit dem env()-Assistenten angegeben wird, können wir verschiedene Logger in verschiedenen Umgebungen verwenden, z. B. Datei in der lokalen Umgebung und Datenbank in der Produktionsumgebung.

Zusammenfassung

Die Verwendung von Schnittstellen ermöglicht es uns, Code mit geringer Kopplung zu schreiben und eine Abstraktionsschicht bereitzustellen. Es ermöglicht uns, die Implementierung jederzeit zu ändern. Versuchen Sie daher, die variablen Teile Ihrer Anwendung möglichst schnittstellenorientiert umzusetzen.

Empfohlenes Tutorial: „PHP-Tutorial

Das obige ist der detaillierte Inhalt vonLaravel-Schnittstellenorientierte Programmierung (Praxis). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:learnku.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen