La programmation orientée interface est une philosophie de conception de codage qui crée des applications basées sur des interfaces plutôt que sur des classes fixes.
Si vous êtes programmeur, vous avez peut-être entendu parler de dictons tels que : programmation orientée interface, utilisation de classes abstraites au lieu de classes fixes, etc.
Cela signifie tous la même chose : écrire le code de l'application pour qu'il repose sur des interfaces abstraites plutôt que sur des classes concrètes.
Pourquoi ?
C'était exactement ma réaction lorsque j'ai entendu cette phrase pour la première fois. Pourquoi utiliser des interfaces plutôt que des classes ? Même si l'interface est créée, je dois créer une classe qui implémente l'interface. N'est-ce pas une perte de temps ?
Bien sûr que non ! !
La seule constante dans ce monde est le changement lui-même, c'est-à-dire que le changement est éternel.
En ce qui concerne la programmation, il n'y a aucune exception à cela. À mesure que les besoins des entreprises évoluent au fil du temps, notre code doit également évoluer.
Le code doit donc rester flexible.
La programmation orientée interface peut rendre le code faiblement couplé et flexible.
Comment faire ?
Observez le code ci-dessous.
class Logger { public function log($content) { //日志保存到文件中. echo "Log to file"; } }
Il s'agit d'une classe simple qui se connecte à un fichier. Nous pouvons l'appeler dans le contrôleur.
class LogController extends Controller { public function log() { $logger = new Logger; $logger->log('Log this'); } }
Mais que devons-nous faire si nous devons enregistrer des journaux à plusieurs endroits (tels que des bases de données, des fichiers, des nuages, etc.).
Nous pouvons ensuite modifier les classes LogController et Logger pour s'adapter à ces changements.
class Logger { public function logToDb($content) { //将日志记录到 db. } public function logToFile($content) { //将日志保存到 file. } public function logToCloud($content) { //将日志存储到 cloud. } }
Maintenant, nous pouvons enregistrer différents objectifs. Mais que se passe-t-il si nous voulons ajouter d'autres cibles (telles que des journaux) au serveur Redis ? Enfin, nous modifierons à la fois la classe Logger et la classe LogController.
Comme vous pouvez le constater, cela est rapidement devenu hors de notre contrôle et le code est devenu encombré. La classe Logger est rapidement devenue un tout. C'est un cauchemar.
Donc, nous devons diviser les choses. En suivant les principes SOLID, nous pouvons transférer les responsabilités vers les classes appropriées.
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); } } }
et le contrôleur devient :
class DBLogger { public function log() { //将日志记录到 db } } class FileLogger { public function log() { //将日志保存到 file } } class CloudLogger { public function log() { //将日志存储到 cloud } }
C'est bien mieux. Maintenant, si nous voulons ajouter des cibles de journalisation supplémentaires, nous pouvons créer une nouvelle classe et l'ajouter au if-else dans le contrôleur.
Cependant, notre contrôleur est toujours responsable de la sélection de l'enregistreur. Pour le contrôleur, il n’est pas nécessaire de connaître les différents enregistreurs et de choisir entre eux. Cela nécessite simplement une classe logger avec une méthode log() pour enregistrer le contenu.
Utilisation des interfaces
Cette situation est adaptée à l'utilisation des interfaces. Alors, qu’est-ce qu’une interface ?
Une interface est une description des opérations qu'un objet peut effectuer.
Pour notre exemple, le contrôleur n'a besoin que de la classe logger avec la méthode log(). Par conséquent, notre interface doit décrire qu’elle doit avoir une méthode log().
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); } } }
Comme vous pouvez le voir, il ne contient que la déclaration de la fonction et non son implémentation, c'est pourquoi on l'appelle abstrait.
Lors de l'implémentation d'une interface, la classe qui implémente l'interface doit fournir les détails d'implémentation des méthodes abstraites définies dans l'interface.
Dans notre exemple, toute classe qui implémente l'interface Logger doit fournir les détails d'implémentation de la méthode abstraite log ().
On peut ensuite injecter cette interface dans le contrôleur.
interface Logger { public function log($content); }
Maintenant, le contrôleur ne se soucie plus du type d'enregistreur qui lui est transmis. Tout ce qu'il doit savoir, c'est qu'il doit implémenter l'interface Logger.
Par conséquent, nous devons modifier la classe Logger pour implémenter cette interface.
class LogController extends Controller { public function log(Logger $logger) { $logger->log($content); } }
Nous pouvons désormais ajouter plus d'enregistreurs sans toucher au code existant. Tout ce que nous avons à faire est de créer une nouvelle classe qui implémente l'interface Logger.
class DBLogger implements Logger { public function log() { //将日志记录到 db } } class FileLogger implements Logger { public function log() { //将日志存储到 file } } class CloudLogger implements Logger { public function log() { //将日志保存到 cloud } }
Notre code semble désormais flexible et faiblement couplé. Nous pouvons modifier l'implémentation à tout moment sans modifier le code précédent.
Injection de dépendances
Lorsque nous utilisons le framework Laravel, nous pouvons utiliser le conteneur de service pour enregistrer automatiquement l'implémentation de l'interface.
Étant donné que Laravel fournit une injection de méthode prête à l'emploi, il nous suffit de lier l'interface et l'implémentation.
Nous devons d’abord créer un fichier de configuration de l’enregistreur. Juste comme ça
class RedisLogger implements Logger { public function log() { //将日志存储到 redis } }
Ensuite, ajoutez le code suivant au fichier AppServiceProvider.php sous le chemin app/Providers
<?php return [ 'default' => env('LOG_TARGET', 'file'), 'file' => [ 'class' => App\Log\FileLogger::class, ], 'db' => [ 'class' => App\Log\DBLogger::class, ], 'redis' => [ 'class' => App\Log\RedisLogger::class, ] ];
L'effet de ceci est de lire l'enregistreur par défaut à partir de la configuration logger.php Puis liez-vous à l'interface Logger. De cette façon, lorsque nous utilisons l'interface Logger, le conteneur analysera et renverra pour nous l'instance Logger par défaut.
Étant donné que l'enregistreur par défaut est spécifié à l'aide de l'assistant env(), nous pouvons utiliser différents enregistreurs dans différents environnements, tels qu'un fichier dans l'environnement local et une base de données dans l'environnement de production.
Résumé
L'utilisation d'interfaces nous permet d'écrire du code à faible couplage et de fournir une couche d'abstraction. Cela nous permet de modifier la mise en œuvre à tout moment. Par conséquent, essayez d’implémenter autant que possible les parties variables de votre application de manière orientée interface.
Tutoriel recommandé : "Tutoriel PHP"
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!