Есть ли что-то не так с незамедлительно принятием меры в конструкторах?

У меня есть классы как этот:

class SomeObject
{
    public function __construct($param1, $param2)
    {
       $this->process($param1, $param2);
    }
    ...
}

Таким образом, я могу немедленно "назвать" его как своего рода глобальную функцию точно так же, как

new SomeObject($arg1, $arg2);

который обладает преимуществами

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

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

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

Разъяснение:

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

Пример:

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

new Email('to@example.com', 'Subject line', 'Body Text');

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

15
задан pestaa 19 May 2010 в 20:41
поделиться

8 ответов

если код в конструкторе является частью создания и инициализации объекта для использования, то я бы поместил его туда, но это я лично, некоторые люди могут не согласиться

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

Оставьте конструктор для построения.

8
ответ дан 1 December 2019 в 03:52
поделиться

Это кратко, но далеко не идиоматично, поэтому другим нелегко понять.

В будущем вам, возможно, будет нелегко это понять.

Это может быть не важно для вас, но одна проблема с этим состоит в том, что ваши классы труднее тестировать - см. Недостаток: Конструктор выполняет настоящую работу .

0
ответ дан 1 December 2019 в 03:52
поделиться

Я думаю, что это плохая практика по двум причинам.

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

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

Что касается второго пункта... если конструктор содержит операцию, которая непредсказуемо выбрасывает исключения (в отличие от исключений, выбрасываемых, например, из-за проверки параметров), то ваш код обработки исключений становится неудобным. Рассмотрим следующий пример на C#. Обратите внимание, что хороший дизайн выглядит более элегантно. Неважно, что четко названный метод, по крайней мере, на порядок более читабелен.

public class BadDesign : IDisposable
{
  public BadDesign()
  {
    PerformIOBoundOperation();
  }

  private void PerformIOBoundOperation() { }
}

public class GoodDesign : IDisposable
{
  public GoodDesign()
  {

  }

  public void PerformIOBoundOperation() { }
}

public static void Main()
{
  BadDesign bad = null;
  try
  {
    bad = new BadDesign();
  }
  catch
  {
    // 'bad' is left as null reference. There is nothing more we can do.
  }
  finally
  {
    if (bad != null)
    {
      bad.Dispose();
    }
  }

  GoodDesign good = new GoodDesign();
  try
  {
    good.PerformIOBoundOperation();
  }
  catch
  {
    // Do something to 'good' to recover from the error.
  }
  finally
  {
    good.Dispose();
  }
}
1
ответ дан 1 December 2019 в 03:52
поделиться

На мой взгляд, это зависит от цели функции.

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

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

Если у вас есть объект, который выполняет какую-либо обработку на входе, я бы определенно избегал

s = new MyObject(a, b)
return s.getResult()

в пользу

s = new MyObject() // perhaps this is done elsewhere, even once at startup
return s.process(a, b)

, поскольку, возможно, последний более ясен относительно того, что на самом деле происходит (особенно если вы дадите ] process () настоящее имя :-)), и позволяет повторно использовать один, более легкий объект для вычислений, что, в свою очередь, упрощает передачу.

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

0
ответ дан 1 December 2019 в 03:52
поделиться

Это плохая практика.

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

Если вам нужна глобальная функция, объявите ее:

function myGlobalFunction(){ return $something; }

На самом деле это не так уж и сложно ...

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

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

Если вам нужно всегда предпринимать определенные действия после создания нового экземпляра класса, попробуйте фабрику:

 class myFactory{
       public static function makeObject(){
           $obj = new Object();
           $obj->init1();
           return $obj;
       }
 }

 $obj = myFactory::makeObject();
5
ответ дан 1 December 2019 в 03:52
поделиться

Бритва Оккама гласит entia non sunt multiplicanda praeter needitatem , буквально: «сущности не должны умножаться сверх необходимости». Нет ничего плохого в выполнении работы в конструкторе [*], но от вызывающих не требуется создавать объект, который они не используют, просто чтобы получить побочные эффекты его конструктора.

[*] Предполагается, что вы знакомы с механизмом, который использует ваш язык программирования для индикации сбоя конструктора. Возврат кода успеха / сбоя из конструктора может быть неприемлемым, поэтому, если вы хотите избежать исключения в случае сбоя, вам может понадобиться установить в объекте флаги «годен для использования», что не очень хорошо. по удобству использования тоже.

4
ответ дан 1 December 2019 в 03:52
поделиться

То, чего следует опасаться в отношении этого паттерна:

  • Нарушение принципа единой ответственности
  • Реализация антипаттерна функциональной декомпозиции
  • Несоответствие ожиданиям обычных потребителей

Принцип единой ответственности

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

Антипаттерн функциональной декомпозиции

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

Общие ожидания потребителей

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

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

Приемлемое использование?

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

/* This is a common usage of this class */
File f;
f.Open(path);

/* This constructor constructs the object and puts it in the open state in one step 
 * for convenience */
File f(path);

Но даже это сомнительно. Хранит ли класс file внутренний путь к файлу или он используется только для открытия дескриптора файла? Если он хранит путь к файлу, то теперь Open() и новый конструктор несут более одной ответственности (SetPath(p) и Open()). В таком случае, возможно, удобному конструктору File(path) не следует открывать файл, а лучше просто установить путь в объекте.

Есть много соображений, основанных на рассматриваемых объектах. Подумайте о написании модульных тестов для ваших объектов. Они помогут вам решить многие из этих вопросов.

1
ответ дан 1 December 2019 в 03:52
поделиться

Ваш класс технически хорош, и это может просто сводиться к личной философии.

но тем, кто читает это и может прийти в голову сумасшедшее представление о конструкторах, прочтите это:

http://www.ibm.com/developerworks/java/library/j-jtp0618.html

Если вы ' Если вы начнете перебрасывать ссылку «this», вы можете столкнуться с большим количеством проблем, особенно в многопоточных средах. Просто к вашему сведению.

0
ответ дан 1 December 2019 в 03:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: