PHP ООП: интерфейс против неинтерфейсного подхода - примеры - PullRequest
5 голосов
/ 07 марта 2012

Можно достичь того же, используя разные инструменты. Я тоже в примерах ниже.

Один показывает использование интерфейса / полиморфизм (источник: nettuts - я думаю). Еще одно простое взаимодействие с классом (мое), которое также показывает некоторый полиморфизм (через call_tool ()).

Не могли бы вы сказать мне, что вы считаете лучшим способом.

Что является более безопасным, более стабильным, защищенным от несанкционированного доступа и пригодным для будущего (в отношении разработки кода).

Пожалуйста, внимательно изучите область видимости, используемую в обоих.

Ваши общие рекомендации, так как это лучшая практика кодирования.

ИНТЕРФЕЙС:

class poly_base_Article {

    public $title;
    public $author;
    public $date;
    public $category;

    public function __construct($title, $author, $date, $category = 0, $type = 'json') {
        $this->title = $title;
        $this->author = $author;
        $this->date = $date;
        $this->category = $category;

        $this->type = $type;
    }

    public function call_tool() {
        $class = 'poly_writer_' . $this->type . 'Writer';
        if (class_exists($class)) {
            return new $class;
        } else {
            throw new Exception("unsupported format: " . $this->type);
        }
    }

    public function write(poly_writer_Writer $writer) {
        return $writer->write($this);
    }

}

interface poly_writer_Writer {

    public function write(poly_base_Article $obj);
}

class poly_writer_xmlWriter implements poly_writer_Writer {

    public function write(poly_base_Article $obj) {
        $ret = '';
        $ret .= '' . $obj->title . '';
        $ret .= '' . $obj->author . '';
        $ret .= '' . $obj->date . '';
        $ret .= '' . $obj->category . '';
        $ret .= '';
        return $ret;
    }

}

class poly_writer_jsonWriter implements poly_writer_Writer {

    public function write(poly_base_Article $obj) {
        $array = array('article' => $obj);
        return json_encode($array);
    }

}

$article = new poly_base_Article('Polymorphism', 'Steve', time(), 0, $_GET['format']);
echo $article->write($article->call_tool());

NON-ИНТЕРФЕЙС

class npoly_base_Article {

    public $title;
    public $author;
    public $date;
    public $category;

    public function __construct($title, $author, $date, $category = 0, $type = 'json') {
        $this->title = $title;
        $this->author = $author;
        $this->date = $date;
        $this->category = $category;
        $this->type = $type; //encoding type - default:json
    }

    public function call_tool() {
        //call tool function if exist
        $class = 'npoly_writer_' . $this->type . 'Writer';
        if (class_exists($class)) {
            $cls = new $class;
            return $cls->write($this);
        } else {
            throw new Exception("unsupported format: " . $this->type);
        }
    }

}

class npoly_writer_jsonWriter {

    public function write(npoly_base_Article $obj) {
        $array = array('article' => $obj);
        return json_encode($array);
    }

}

class npoly_writer_xmlWriter {

    public function write(poly_base_Article $obj) {
        $ret = '';
        $ret .= '' . $obj->title . '';
        $ret .= '' . $obj->author . '';
        $ret .= '' . $obj->date . '';
        $ret .= '' . $obj->category . '';
        $ret .= '';
        return $ret;
    }

}

$article = new npoly_base_Article('nPolymorphism', 'Steve', time(), 0, $_GET['format']);
echo$article->call_tool();

код MikeSW (если я правильно понял)

 class poly_base_Article {

    private $title;
    private $author;
    private $date;
    private $category;

    public function __construct($title, $author, $date, $category = 0) {
        $this->title = $title;
        $this->author = $author;
        $this->date = $date;
        $this->category = $category;
    }

    public function setTitle($title) {
        return $this->title = $title;
    }

    public function getTitle() {
        return $this->title;
    }

    public function getAuthor() {
        return $this->author;
    }

    public function getDate() {
        return $this->date;
    }

    public function getCategory() {
        return $this->category;
    }


}

interface poly_writer_Writer {

    public function write(poly_base_Article $obj);
}

class poly_writer_xmlWriter implements poly_writer_Writer {

    public function write(poly_base_Article $obj) {

        $ret = '';
        $ret .= '' . $obj->getTitle() . '';
        $ret .= '' . $obj->getAuthor() . '';
        $ret .= '' . $obj->getDate() . '';
        $ret .= '' . $obj->getCategory() . '';
        $ret .= '';
        return $ret;
    }

}

class poly_writer_jsonWriter implements poly_writer_Writer {

    public function write(poly_base_Article $obj) {
        //array replacement
        //$obj_array = array('title' => $obj->getTitle(), 'author' => $obj->getAuthor(), 'date' => $obj->getDate(), 'category' => $obj->getCategory());
        //$array = array('article' => $obj_array);

        $array = array('article' => $obj); //$obj arrives empty
        return json_encode($array);
    }

}

class WriterFactory {

    public static function GetWriter($type='json') {
        switch ($type) {
            case 'json':
            case 'xml': $class = 'poly_writer_' . $type . 'Writer';
                return new $class;
                break;
            default: throw new Exception("unsupported format: " . $type);
        }
    }

}

$article = new poly_base_Article('nPolymorphism', 'Steve', time(), 0);
$writer=WriterFactory::GetWriter($_GET['format']);

echo $writer->write($article);

Ответы [ 2 ]

2 голосов
/ 07 марта 2012

Гм, у ваших подходов есть недостатки, независимо от того, какая версия.Во-первых, poly_base_Article выставляет поля, которые нарушают инкапсуляцию и, в первую очередь, побеждают цель использования ООП.

Далее, у вас есть точная инъекция через параметр $ _GET.Надлежащий способ сделать класс должен быть таким:

 class poly_base_Article {

private $title;
private $author;
private $date;
private $category;

public function __construct($title, $author, $date, $category = 0) {
    $this->title = $title;
    $this->author = $author;
    $this->date = $date;
    $this->category = $category;

}

 public function getTitle() { return $this->title;}
 //...other getters defined here...

   public function AsArray()
     { 
          return (array) $this;
     }

//this could be removed
public function write(poly_writer_Writer $writer) {
    return $writer->write($this);
}
}

Метод write , похоже, не требуется, вы просто говорите автору писать объект напрямую.

Метод * call_tool * должен принадлежать службе или как фабричный метод для создания экземпляра poly_writer_Writer (кстати, вы должны изменить наименование классов и интерфейса на что-то более естественное), что-то вроде этого

class WriterFactory
 {
     public static function GetWriter($type='json')
      {
         switch($type)
         {
            case 'json'
            case 'xml': $class= 'poly_writer_' . $type . 'Writer'; 
             return new $class;
              break;
             default: throw new Exception("unsupported format: " . $type);
           }
        }
 }


  $article = new poly_base_Article('nPolymorphism', 'Steve', time(), 0);
   $writer=WriterFactory::GetWriter(, $_GET['format']);
 echo $writer->write($article);

Что является более безопасным, более стабильным, защищенным от несанкционированного доступа и пригодным для будущего (в отношении разработки кода).

Это зависит только от навыков и дисциплины разработчика.В этом конкретном случае код, который я написал, является более безопасным, защищенным от несанкционированного доступа и надежным на будущее: P

Обновление Действительно, я забыл поместить геттеры в poly_base_Article, я добавилих сейчас.Так как вы делаете сериализацию, статья не должна знать об этом, так как это не его ответственность (это часть уровня инфраструктуры), поэтому метод записи вообще не требуется, но здесь есть особый случай (все зависитв контексте).

WriterFactory - это в основном фабричный шаблон, который создает экземпляр модуля записи и возвращает абстракцию - это полиморфизм, в котором интерфейс полезен.Этот подход позволяет очень легко добавлять новые реализации интерфейса, а также защищать от внедрения кода. Переключатель должен проверять, разрешены ли только допустимые значения типа $.Вы можете проверить тип $ в других местах, но это единственное место, которое должно обрабатывать все, что связано с созданием писателей.Даже если вы хотите проверить вне его, вы просто создаете статический метод в WriterFactory, который будет возвращать true / false и использовать than.

Об интерфейсах, являющихся модой ... использование интерфейсов - это то, как ООП должно быть сделано.Лучше всего программировать против абстракции, а интерфейсы являются «лучшей» абстракцией.Проще говоря: если интерфейсы - это причуды, то ООП - это причуды.

О вашем втором примере, ну и первый тоже, метод, который создает писателя, не должен быть там во-первых, так как он соединяетсятворчество автора статьи и тех двоих не имеет ничего общего.Это нарушение SRP (принцип единой ответственности).

В этом конкретном случае, когда вы выполняете фабрику создания в отдельном классе, вам почти все равно, какие интерфейсы вам нужны, поскольку использование здесь очень упрощено, и вы используете PHP илиязык свободного типа.Если вы передадите писателя как зависимость, это поможет обойти интерфейс, а не реальную реализацию (как вы это делали в первом примере).Очень полезно знать, какой тип вы передаете.

Кроме того, на языке, подобном C #, у вас будет тип возврата, а затем, в качестве оптимального использования, вы вернете его как тип интерфейса (C #поддерживает динамические типы, которые, скажем, ведут себя немного как в PHP, так что вы можете возвращать динамические и не заботящиеся, но это приводит к снижению производительности, и если возвращенный тип не имеет вызванного метода, он выдаст исключение)

1 голос
/ 08 марта 2012

Я бы начал все с того, что порекомендовал это видео и другие видео из серии.

Есть два условия, которые делают интерфейсы предпочтительными:

  • вы работаете в команде
  • долгосрочный проект

Использование интерфейсов действует как другой набор документации, когда вам нужно расширить функциональность вашей кодовой базы. Также тогда используется принцип наименьшего удивления .

В очень маленьком и быстром проекте нет смысла использовать интерфейсы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...