Есть ли причина создавать класс для одной функции? - PullRequest
13 голосов
/ 21 июня 2011

Я видел много классов с функцией SINGLE .Почему они помещают функцию SINGLE в класс?

Я использую классы только для того, чтобы прояснить ситуацию, но для тех, кто помещает функцию SINGLE в класс?Есть ли какая-то причина для этого?

Я не вижу разницы между ними:

<?php
class Image {
    private $resource;
    function resize($width, $height) {
        $resized = imagecreatetruecolor($width, $height);
        imagecopyresampled($resized, $this->resource, 0, 0, 0, 0, $width, $height, imagesx($this->resource), imagesy($this->resource));
        $this->resource = $resized;
    }
}
$image = new Image();
$image->resource = "./someimage.jpg";
$image->resize(320, 240);

и

    function resize($width, $height) {
        $resource = "./someimage.jpg";    
        $resized = imagecreatetruecolor($width, $height);
        imagecopyresampled($resized, $resource, 0, 0, 0, 0, $width, $height, imagesx($resource), imagesy($resource));
        $resource = $resized;
        return $resource;
    }

resize(320, 240);

Я думал, что $ resource является основной причиной, потому что он частный:

class Image {
    private $resource;
    function resize($width, $height) {
        $resized = imagecreatetruecolor($width, $height);
        imagecopyresampled($resized, $this->resource, 0, 0, 0, 0, $width, $height, imagesx($this->resource), imagesy($this->resource));
        $this->resource = $resized;
    }
}

$image->resize(320, 240);

и, следовательно, недоступен для глобальной области.Но почему в этом случае не используется простая функция?

Ответы [ 10 ]

28 голосов
/ 21 июня 2011

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

Иногда может существовать класс объекта, которому нужен только один определенный для него метод, но тем не менее он принадлежит только этому классу объекта.

9 голосов
/ 21 июня 2011

Я в основном занимаюсь встроенным программированием и редко использую классы. Но один класс функций может быть использован для -

  • унаследовано позже
  • обеспечивает целостность структуры данных, которая является частной по отношению к классу (инкапсуляция).
  • может использоваться для поддержания однородности кода.
7 голосов
/ 21 июня 2011

Почему некоторые функции содержат только одну строку кода? Потому что это все, что нужно. Теперь вы можете вызывать функцию, а не повторять одну строку кода везде. Если эту строку кода необходимо настроить, это должно произойти только в одном месте. Это использует процедурную инкапсуляцию.

То же самое касается вашего краткого класса. Теперь вы можете использовать все возможности классов, особенно наследование и полиморфизм, скажем, SVGImage extends Image и метод переопределения resize.

.

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

6 голосов
/ 12 октября 2011

На самом деле это хороший вопрос, и я видел здесь несколько хороших ответов. На самом деле мне действительно пришлось немного подумать об этом.

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

Давайте возьмем ваши примеры. (Я отредактировал их так, чтобы они были функционально идентичны - они немного изменились по сравнению с тем, что было выше.)

Версия класса:

<?php
class Image {
    private $resource;
    function resize($width, $height) {
        $resized = imagecreatetruecolor($width, $height);
        imagecopyresampled($resized, $this->resource, 0, 0, 0, 0, $width, $height, imagesx($this->resource), imagesy($this->resource));
        $this->resource = $resized;
    }
}
$image = new Image();
$image->resource = "./someimage.jpg";
$image->resize(320, 240);

И версия функции:

    function resize($width, $height, $resource) {
        $resized = imagecreatetruecolor($width, $height);
        imagecopyresampled($resized, $resource, 0, 0, 0, 0, $width, $height, imagesx($resource), imagesy($resource));
        $resource = $resized;
        return $resource;
    }

resize(320, 240, "./someimage.jpg");

На практике они функционально идентичны. Основным отличием является просто парадигма ООП и процедурная парадигма; в ООП вы определяете функцию внутри класса (это называется методом), которая действует на переменную-член, тогда как в процедурной программе вы передаете эту переменную в функцию, определенную в глобальной области видимости.

Итак, в чем же преимущество переноса функции в классе вместо того, чтобы делать ее глобальной, поскольку функция все еще делает то же самое?

Основная причина, по которой вы хотите сделать это в PHP (и во многих других языках, о которых я могу подумать), это область действия. @Headspin кратко упомянул об этом. Определение функции resize в глобальной области видимости все хорошо, пока вам не понадобится другая функция с тем же именем. Что происходит?

Обычно вы сталкиваетесь с одним из следующих решений:

  1. (Хорошо.) Ваш язык поддерживает перегрузку функций, поэтому вы не должны беспокоиться об этом, пока ваши аргументы отличаются.
  2. (Плохо.) Ваш язык не поддерживает перегрузку функций (или ваши аргументы должны быть идентичны), поэтому вы прибегаете к подробным именам (например, resize_image, resize_container) и т. Д.
  3. (Все еще плохо.) Вы начинаете использовать пространства имен для разделения ваших глобальных функций.
  4. (Ужасно.) Ваша функция принимает в качестве аргумента все что угодно и становится горячим, раздутым беспорядком операторов if / then или блоков switch / case для каждого типа переменной, который она будет обрабатывать.

Моя основная причина для инкапсуляции функции в PHP состоит в том, чтобы избежать конфликтов имен, делая код более интуитивным и более легким для понимания. У меня может быть метод изменения размера в моем Image классе, и один в моем Container классе, и, возможно, другой в классе test или что-то в этом роде, и ни один из них не будет конфликтовать друг с другом. Читая код, я знаю, что Image->resize() вызывает метод в классе Image и ничего больше.

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

Полагаю, все, надеюсь, это поможет. Ниже приведена версия TL; DR.

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

6 голосов
/ 21 июня 2011

Вместо того, чтобы рассматривать класс как набор функций, подумайте о роли класса.Классы, как правило, должны знать о том, что он содержит, и ничего о том, чего он не имеет, и должны фиксировать только одну ключевую абстракцию.Могут быть случаи, когда это имеет смысл.

4 голосов
/ 21 июня 2011

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

3 голосов
/ 08 октября 2011

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

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

В-третьих, вы можете использовать автозагрузчик классов с классами, поэтому загружать файл, содержащий этот класс, только если класс действительно используется, а не загружать его каждый раз, когда запускается скрипт, или беспокоиться о том, где разместить операторы include и require.

В-четвертых, и, возможно, наиболее важно, вы можете использовать этот класс и любой другой класс в качестве входных данных для другого класса, позволяя вам изменять функциональные возможности этого класса, просто выбирая, какой класс вставлять. Как пример ...

class ImageProcessingClass {

   protected $imageResource;
   protected $processors = array();

   public function setImageResource($image_resource) {
      $this->imageResource = $image_resource;
   }

   public function addProcessor(Processor $processor) {
      $this->processors[] = $processor;
   }

   public function processImage() {
      foreach ($this->processors as $processor) {
         $this->imageResource = $processor->process($this->imageResource);
      }
   }
}

interface Processor {
   public function process($image);
}

class ProcessorResize implements Processor {

   public function process($image) {
      // resize image code here...
      return $image;
   }
}

class ProcessorFilter implements Processor {

   public function process($image) {
      // filter image code here...
      return $image;
   }
}

и код, который использует это

$image_processor = new ImageProcessor();
$image_processor->setImageResource($image_resource);
$image_processor->addProcessor(new ProcessorResize());
$image_processor->addProcessor(new ProcessorFilter());
$image_resource = $image_processor->processImage();

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

1 голос
/ 12 октября 2011

Согласно Modern Development в php, он очень гибок или надежен в использовании классов.

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

например:

Class A{

      public static function xyz(){
       //function handling
      }
}

A::xyz();
0 голосов
/ 12 октября 2011

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

0 голосов
/ 11 октября 2011

Помимо некоторых веских причин, приведенных выше, о том, зачем заключать в класс хотя бы один метод, есть еще одна:

В C ++, если вы хотите предложить интерфейс даже для всего одного метода,Вы должны определить вызов для этого.

например,

class CallBackClient
{
   public:
   // A callback function. 

  virtual s32 callback( int param1, int param2 ) = 0;
};

Каждый клиент, который хочет предоставить свою собственную реализацию обратного вызова, должен распространиться на этот класс.

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

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