Clase abstracte și interfețe în PHP

Interfețe (Interface)

Trebuie să știm că o interfață este definită de cuvântul cheie de interface și că toate metodele (funcțiile) ei sunt abstracte. Toate metodele declarate într-o interfață trebuie să fie publice; asta este pur și simplu natura unei interfețe și nu poate fi schimbată. Exemplu de interfață:

<?php 
interface Logger {     
    public function execute(); 
} 

Într-o interfață, corpul metodei nu poate fi definit, ca în exemplul de sus, metoda execute nu are corp, deci vom defini doar numele și parametrii funcției (metodei). Pentru a înțelege mai bine ce probleme putem întâlni în cazul în care nu vom folosim o interfață, și invers, de ce ar trebui să folosim o interfața, analizați codul de mai jos:

<?php
class LogToDatabase 
{
    public function execute($message)
    {
        var_dump('log the message to a database :'.$message);
    }
}
class LogToFile 
{
    public function execute($message)
    {
        var_dump('log the message to a file :'.$message);
    }
}
class UsersController 
{ 
    protected $logger;
    
    public function __construct(LogToFile $logger)
    {
        $this->logger = $logger;
    }
    
    public function show()
    { 
        $user = 'author';
        $this->logger->execute($user);
    }
}
$controller = new UsersController(new LogToFile);
$controller->show();

În exemplul de mai sus nu este folosităinterfața. Deci se scrie în jurnal utilizând clasa LogToFile. Însă, dacă vrem să scrim în jurnal folosind LogToDatabase, trebuie să schimbăm codul de mai sus, în loc de codul:

public function __construct(LogToFile $logger)

trebuie să scrim:

public function __construct(LogToDatabase $logger)

Într-un proiect mai mare, dacă avem mai multe clase și este nevoie de o schimbare, atunci trebuie să schimbăm manual toate clasele care folosesc clasa LogToFile . Dar dacă folosim o interfață, această problemă este rezolvată; și nu va trebui să schimbăm tot codul manual.

Urmăriți codul de mai jos și încercați să realizați ce sa întâmplat dacă vom folosi o interfața:

<?php
interface Logger 
{
    public function execute($message);
}
class LogToDatabase implements Logger 
{
    public function execute($message){
        var_dump('log the message to a database :'.$message);
    }
}
class LogToFile implements Logger 
{
    public function execute($message) 
    {
        var_dump('log the message to a file :'.$message);
    }
}
class UsersController 
{
    protected $logger;
    
    public function __construct(Logger $logger) 
    {
        $this->logger = $logger;
    }
    
    public function show() 
    {
        $user = 'author';
        $this->logger->execute($user);
    }
}
$controller = new UsersController(new LogToDatabase);
$controller->show();

Acum, dacă dorim să trecem de la LogToDatabase înapoi la LogToFile nu trebuie să schimbăm manual metoda constructorului (__construct). În metoda constructorului am injectat o interfață; nu o clasă arbitrară. Deci, dacă aveți mai multe clase cu funcțional asemănător și doriți să schimbați de la o clasă la alta, veți obține același rezultat fără a schimba nici o referință de clasă.

În exemplul de mai sus, vom scri în jurnal utilizând LogToDatabase, dar acum, dacă dorim să scrim în jurnal utilizând LogToFile, nu avem decât schimba doar următorul rând de cod:

$controller = new UsersController(new LogToFile);
$controller->show();

Obținem acelaș rezultat fără a schimba alte clase, deoarece interfața se ocupă de această problemă de schimbare.

Clasele Abstracte (Abstract class)

O clasă abstractă este o clasă implementată doar parțial de programator. Poate conține cel puțin o metodă abstractă, care este o metodă fără cod în ea, doar numele și parametrii și care a fost marcată cu cuvântul cheie „abstract„.

O metodă abstractă este pur și simplu este o definiție a funcției care servește pentru a spune programatorului că metoda trebuie implementată într-o clasă copil. Mai jos găsiți un exemplul:

<?php
abstract class AbstractClass
{
    // Forțează classa care o extinde să definească aceasta metodă
    abstract protected function getValue();
    
    public function printOut() 
    {
        print $this->getValue() . "\n";
    }
}

Acum, întrebarea este „când va fi situația că o metodă va fi necesară în clasa care o extinde și trebuie implementată?” Mai josi voi încerca să explic. Vedeți clasa Tea.

<?php
class Tea 
{
    public function addTea()
    {
        var_dump('Add proper amount of tea');
        return $this;
    }
    protected  function  addHotWater()
    {
        var_dump('Pour Hot water into cup');
        return $this;
    }
    
    protected  function addSugar()
    {
        var_dump('Add proper amount of sugar');
        return $this;
    }
    
    protected function addMilk()
    {
        var_dump('Add proper amount of Milk');
        return $this;
    }
    public function make()
    {
        return $this
            ->addHotWater()
            ->addSugar()
            ->addTea()
            ->addMilk();
    }
}
$tea = new Tea();
$tea->make();

Acum vom analiza classa Coffe

<?php
class Coffee 
{
    public function addCoffee()
    {
        var_dump('Add proper amount of coffe');
        return $this;
    }
    protected  function  addHotWater()
    {
        var_dump('Pour Hot water into cup');
        return $this;
    }
    
    protected  function addSugar()
    {
        var_dump('Add proper amount of sugar');
        return $this;
    }
    
    protected function addMilk()
    {
        var_dump('Add proper amount of Milk');
        return $this;
    }
    public function make()
    {
        return $this
            ->addHotWater()
            ->addSugar()
            ->addCoffee()
            ->addMilk();
    }
}
$tea = new Coffee();
$tea->make();

În cele două clase de mai sus, cele trei metode addHotWater(), addSugar() și addMilk() sunt aceleași. Deci, ar trebui să eliminăm codul duplicat. Putem face acest lucru în felul următor:

<?php
abstract class Template
{
    public function make()
    {
        return $this
            ->addHotWater()
            ->addSugar()
            ->addPrimaryToppings()
            ->addMilk();
    }
    
    protected  function  addHotWater()
    {
        var_dump('Pour Hot water into cup');
        return $this;
    }
    
    protected  function addSugar()
    {
        var_dump('Add proper amount of sugar');
        return $this;
    }
    
    protected function addMilk()
    {
        var_dump('Add proper amount of Milk');
        return $this;
    }
    
    protected abstract function addPrimaryToppings();
}
class Tea extends Template
{
    public function addPrimaryToppings()
    {
        var_dump('Add proper amount of tea');
        return $this;
    }
}
$tea = new Tea();
$tea->make();
class Coffee extends Template
{
    public function addPrimaryToppings()
    {
        var_dump('Add proper amount of Coffee');
        return $this;
    }
}
$coffee = new Coffee();
$coffee->make();

Am făcut o clasă abstractă și am numit-o Template. Aici definim addHotWater(), addSugar() și addMilk(); apoi facem o metodă abstractă numită addPrimaryToppings.

Acum, dacă vom face ca clasa Tea să extindă clasa Template, atunci vom obține cele trei metode definite și în plus clasa Tea trebuie să definească metoda addPrimaryToppings(). În mod similar, va fi și cu clasa Coffe.

Deci putem spune că Clasele abstracte extind, interfețele implimentează

Vă mulțumim pentru interes și lectură.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>