Подтвердить что ты не робот

Вставить или в новое?

Что касается использования объектов класса в другом классе, то какая из них лучшая? Чтобы передать объекты класса в инструкции класса _construct или создать новый объект класса?

Пример 1:

class Foo {
    private $bar;

    public function __construct($bar){
       $this->bar = $bar;
   }
}

Или Пример 2:

class Foo {

    private $bar;

    public function __construct(){
        $this->bar= NEW bar;
    }    
}

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

Из того, что я могу понять, преимуществом первого может быть несколько меньше строк кодирования, а в случае с БД, а не с созданием нового соединения. Второй может быть лучше, потому что он более самодостаточен? Во всяком случае, я думал, что попрошу экспертов.

4b9b3361

Ответ 1

Первый. (Этот подход называется Injection Dependency).

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

Для улучшения вашего кода можно было бы ввести намек типа в ваш метод:

class Foo {
    private $bar;

    public function __construct(Bar $bar){
       $this->bar = $bar;
   }
}

Таким образом, могут быть переданы только объекты Bar.


Преимущества инъекции зависимостей

  • Очень читаемый.
  • Возможность указывать зависимости метода без просмотра исходного кода.
  • Возможна установка модулей.
  • * Сохраняет котят от гнева Бога.

* Отказ от ответственности: котятам не было нанесено вреда во время проявления этого ответа

Ответ 2

Вам следует перейти к опции 1, так как это простейшая форма инъекции зависимостей.

В варианте 1:

  • классы не зависят друг от друга
  • классы могут быть протестированы независимо, используя макет для класса bar

Ответ 3

В общем, я бы звонил с толпой DI по причинам, изложенным в Как думать о "новом" операторе в отношении модульного тестирования:

Но причина, по которой Injection Dependency настолько важна, заключается в том, что в модульных тестах вы хотите протестировать небольшое подмножество своего приложения. Требование состоит в том, что вы можете построить это небольшое подмножество приложения независимо от всей системы. Если вы смешиваете логику приложения с построением диаграммы (новый оператор), модульное тестирование становится невозможным для чего угодно, кроме листовых узлов в вашем приложении.

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

Например, если ваш Bar требует Logger, вы бы сделали

class Foo
{
    private $logger;

    public function __construct(LogInterface $logger)
    {
        $this->logger = $logger;
    }
}

И затем вы передаете какую-либо конкретную реализацию, реализующую этот LogInterface, например, Logger Log или StdOutLogger или, возможно, Composite Logger, держащий оба этих элемента. Другим примером может быть объект базы данных. Вы можете создать это один раз в своем бутстрапе, а затем передать его объектам, использующим его.

Если вы сомневаетесь, пойдите с Injection Dependency.

Однако вам не всегда нужно вводить вещи. Это зависит от того, является ли объект (ваша панель) Injectable или Newable. Процитировать Misko Hevery:

Класс Injectable может запрашивать другие Инъекции в своем конструкторе. [...] Инъекции, как правило, имеют интерфейсы, потому что, возможно, нам придется заменить их на реализацию, дружественную тестированию. Тем не менее, Injectable никогда не может запросить не-Injectable (Newable) в своем конструкторе. Это связано с тем, что инфраструктура DI не знает, как создать Newable. [...] Некоторые примеры Newables: Email, MailMessage, User, CreditCard, Song. Если вы сохраните эти различия, ваш код будет легко тестироваться и работать. Если вы нарушите это правило, ваш код будет трудно проверить.

Вкратце, когда у вас есть что-то, что невозможно установить разумно, поскольку оно основано на информации, предоставленной пользователем или во время выполнения, вы можете new его. Это особенно справедливо для объектов Value и типов данных:

class Foo
{
    private $storage;

    public function __construct()
    {
        $this->storage = new SplObjectStorage;
    }
}

Нет смысла вводить SplObjectStorage. Это просто тип данных.

Ответ 4

Другие уже ответили на ваш вопрос - определенно перейдем к первому подходу, который использует Injection Dependency.

Я просто хотел пообщаться с другой популярной альтернативой, о которой вы, возможно, не знаете: с помощью Contentioner Injection Dependency.

Простым примером этого является Pimple; разработанный Фабьеном Потеньером, человеком, стоящим за рамками Symfony.

Пример 3:

# In a bootstrap file...
require_once '/path/to/Pimple.php';

$container = new Pimple();
$container['bar'] = function ($c) {
    return new Bar(/** If bar has dependencies, put them here **/);
};

$container['foo'] = function ($c) {
    return new Foo($c['bar']);
};

# You'd still inject the service using DI, because it not good 
# practice for your objects to rely directly on the container

class Foo {
    private $bar;

    public function __construct($bar){
       $this->bar = $bar;
   }
}

# The difference would be how you call Foo...
$foo = $container['foo'];

# So now your code doesn't need to know about the dependencies, and it easy 
# to change them at any time by making a single change in your configuration

Symfony2 использует более надежный Container, который также доступен как автономный compenent. Но Pimple, вероятно, лучший выбор, если вы не разрабатываете крупномасштабное приложение.

Ответ 5

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

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

Пример С# ниже

    class Foo {
    private IBar bar;

    public Foo(IBar obj){
       this.bar = obj;
   }

   public void myFooMethod()
   {
      bar.ExecuteMethod();
   }
}

Класс, вызывающий FOO

    public class MyCallingClass
    {

       public void CallFooMethod()
       {
          IBar bar1Obj = new BAR1();
          Foo fooObject = new Foo(bar1Obj);
          fooObject.ExecuteMethod();
//or
          IBar bar2Obj = new BAR2();
          fooObject = new Foo(bar2Obj);
          fooObject.ExecuteMethod();
//or
          IBar bar3Obj = new BAR3();
          fooObject = new Foo(bar3Obj);
          fooObject.ExecuteMethod();

       }

    }

Теперь мой вызывающий класс может передать любую реализацию IBar классу FOO.

Надеюсь, что это помогло.

Ответ 6

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

Вместо этого я предлагаю вам реализовать оба решения:

class Foo {
    private $bar;

    public function __construct($bar = null){
       $this->bar = isset($bar) ? $bar : new Bar();
   }
}

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