Понимание использования интерфейса и абстрактного класса в PHP

Ромчик
0

Доброго времени суток. В интернете нашел интересную статью о понимании использования интерфейсов и абстрактных классов в PHP. Разницу между ними. И решил сделать перевод (но немножко дополненный), т.к. статья наглядно показывает нам, как и когда использовать интерфейсы и абстрактные классы. И так, поехали…

Интерфейс

Давайте обратимся к официальной документации PHP и посмотрим определение интерфейса:

Интерфейсы объектов позволяют создавать код, который указывает, какие методы должен реализовать класс, без необходимости определять, как именно они должны быть реализованы.

Интерфейс в PHP определяется, как и класс за исключением вместо ключевого слова class мы указываем interface.

Все методы интерфейса являются абстрактными и открытыми – это природа интерфейса. Пример объявления интерфейса:

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

В интерфейсе тело метода не определено, мы определяем только имя и параметры. Теперь давайте рассмотрим, когда использовать интерфейс. Например, у нас есть следующий код:

<?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 = 'nahid';
        $this->logger->execute($user);
    }
}
$controller = new UsersController(new LogToFile);
$controller->show();

В приведенном выше примере автор не использует интерфейс. Автор пишет в журнал, используя класс LogToFile. Но если мы захотим писать данные в журнал с использованием класса LogToDatabase. Необходимо изменить жестко закодированную ссылку на класс:

public function __construct(LogToFile $logger)

Заменить на:

public function __construct(LogToDatabase $logger)

В большом проекте, когда есть несколько классов, это нужно сделать для каждого класса в ручную. Но если, мы будем использовать интерфейс, то это проблема будет решена. И нам не нужно будет менять код в ручную. Теперь давайте рассмотрим следующий код, в котором уже используется интерфейс:

<?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 = 'nahid';
        $this->logger->execute($user);
    }
}
$controller = new UsersController(new LogToDatabase);
$controller->show();

Теперь, если мы записываем данные не LogToDatabase, а с помощью LogToFile нам не нужно менять метод конструктора в ручную. В методе конструктора мы вводим интерфейс. Поэтому, если у вас есть несколько классов и вы переключаетесь с одного класса на другой, вы получите тот же результат без изменения каких-либо ссылок на классы.
В приведенном выше примере автор пишет данные в журнал, используя LogToDatabase, и теперь, если захочет записать данные в журнал, используя LogToFile, то можно просто заменить:

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

Таким образом мы получаем результат без изменения других классов.

Абстрактный класс

Давайте посмотрим официальную документацию PHP для того, чтобы понять что такое абстрактный класс.

PHP 5 поддерживает определение абстрактных классов и методов. Объекты классов, определенных как абстрактные, не могут быть созданы, и любой класс, который содержит по крайней мере один абстрактный метод, должен быть определен как абстрактный. Методы, объявленные абстрактными, несут, по существу, лишь описательный смысл и не могут включать реализацию.

Рассмотрим пример:

<?php
abstract class AbstractClass
{
    // Force Extending class to define this method
    abstract protected function getValue();
    
    public function printOut() 
    {
        print $this->getValue() . "\n";
    }
}

Когда использовать абстрактный класс?

Например, давайте рассмотрим класс 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();

Теперь рассмотрим класс Coffee:

class Coffee 
{
    public function addCoffee()
    {
        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()
            ->addCoffee()
            ->addMilk();
    }
}
$tea = new Coffee();
$tea->make();

В приведенных выше классах три метода addHotWater(), addSugar(), addMilk() одинаковы. Поэтому мы должны удалить дублированный код:

<?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();

Автор создает абстрактный класс и называет его Template. В этом классе определяет три метода addHotWater (), addSugar () и addMilk () и создает абстрактный метод с именем addPrimaryToppings.

Теперь, если создавать класс Tea его необходимо делать расширенным для класса Template, тогда мы получаем три определенных метода и должны определить метод addPrimaryToppings ().

Точно так же и для класса Coffee.

Перевод статьи «Understanding use of Interface and Abstract class»

Понравилась статья? Поделись с друзьями.
  • Add to favorites
  • Добавить ВКонтакте заметку об этой странице
  • Twitter
  • Facebook
  • Мой Мир
  • LiveJournal
  • Одноклассники
  • Блог Я.ру
  • MySpace
  • FriendFeed
  • В закладки Google
  • Google Buzz
  • Яндекс.Закладки
  • Reddit
  • StumbleUpon
  • Technorati
  • del.icio.us
  • БобрДобр
  • LinkedIn
  • Memori.ru
  • Сто закладок
  • Blogger
PHP

©2012-2019 По всем вопросам обращайтесь через форму обратной связиПолитика конфиденциальности

Яндекс.Метрика