Является ли метод «запуска», «запуска» или «выполнения» хорошей практикой?

30

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

Когда целесообразно использовать метод запуска вместо обычной конструкции объекта?

Когда мне лучше использовать конструктор?

Редактировать: я не думаю, что это актуально, но язык программирования - C #, он может в равной степени относиться к Java или C ++

Дэйв Хиллиер
источник
3
Не могли бы вы добавить немного больше контекста? Язык? Резьба против одного потока? Разница между startконструктором и? и т. д.
@MichaelT Я понимаю, почему ты спрашиваешь, но меня интересует общий принцип, когда это уместно. Я обеспокоен тем, что если бы я дал конкретные примеры из кодовой базы, над которой я работаю, ответы были бы слишком сфокусированы на деталях, а не на моих конкретных вопросах.
Дейв Хиллиер,
2
@DaveHillier Например, в perl это стандартная практика (и хорошая), чтобы иметь какой-то initметод вне newфункции - perldoc.perl.org/perlobj.html . Идиомы одного языка могут хорошо работать там, а не на других языках.
1
Примеры классов с Startметодами в общих API включают потоки и секундомеры.
luiscubal
1
Посчитайте меня среди тех, кому нужен пример кода, чтобы понять, что вы на самом деле спрашиваете.
user16764

Ответы:

44

Start()Метод (например Run(), Execute()или что - нибудь подобное) уместно , когда стоимость строительства объекта является низкой, но стоимость используя его высока. Например: класс, который инкапсулирует алгоритм оптимизации наилучшего пути. Тривиально настроить его с помощью набора параметров ( Xквадраты на Yквадраты, с таким и таким методом оценки), но выполнение может занять некоторое время. Если вы хотите создать 20 из этих объектов, вы можете отложить выполнение до тех пор, пока все они не будут созданы - например, это позволяет упростить их распараллеливание.

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

Это предполагает, конечно, что Start()это полезный метод объекта, а не эквивалент Initialize()метода. Если это просто дополнительный способ установить больше параметров, он не должен существовать.

Bobson
источник
1
Другое использование метода start - это когда выполняемое действие также создает новый рабочий поток или таймер. Конструктор не должен выполнять такую ​​тяжелую работу или создавать значительные побочные эффекты (например, создавать новую нить).
Зив
50

Code Complete (и многие другие ресурсы по разработке программного обеспечения) подчеркивают соответствие ваших классов объектам реального мира. Я полагаю, что фундаментальная причина этого заключается в том, что это повышает вероятность того, что вы действительно понимаете, что именно вы реализуете, а не разбиваете на нематериальную идею.

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

Дэн Альберт
источник
16
Хорошая аналогия. Стоит отметить, что он Start()может соответствовать либо переключателю включения / выключения (например, выключателю освещения), который затем должен иметь Stop(), либо кнопке (например, кнопке «Печать» на копировальном аппарате), где он срабатывает, а затем запускается до завершения.
Бобсон
3
+1 хорошо сказано и добро пожаловать в P.SE, такие ответы - отличное начало.
Джимми Хоффа
14

Вы можете использовать ленивую инициализацию.

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

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

Отложите дорогостоящую инициализацию, пока она не понадобится

Пример:

public class FooClass{

    private ExpensiveResource resource;
    private CheapResource cheap;

    public  FooClass(String someParameter){
        // constructor: initialize CheapResource cheap 
            // but NOT ExpensiveResource resource
    }

    public ExpensiveResource getExpensiveResource(){
        if (resource == null) {
            this.initializeExpensiveResource();     
        }
        return this.resource
    }

    public String getExpensiveResourceName(){
        if (resource == null) {
            this.initializeExpensiveResource();     
        }
        return this.resource.getName();
    }   

    public CheapResource getCheapResource(){
        return this.cheap;
    }

    private initializeExpensiveResource(){
        // do expensive initialization of field "resource"
    }

}

public class Test{
    public static void main (String args[]){

        FooClass foo = new FooClass("some string");
        CheapResource cr = foo.getCheapResource();
        String s = foo.getExpensiveResourceName(); 
          // just now is the expensive resource initialized

    }
}
Тулаинс Кордова
источник
5
Еще одно преимущество ленивой инициализации, которое стоит отметить, заключается в том, что для его преобразования в виртуальный прокси требуется очень мало усилий . В зависимости от ситуации это может быть очень полезно для отображения чего-либо во время ожидания загрузки ресурса (особенно полезно для таких вещей, как удаленные образы). Исходя из первоначального вопроса, я не думаю, что это на самом деле то, для чего готовился ОП, но подумал, что стоит упомянуть.
Дэн Альберт
@DanAlbert вы правы, это не то, что я просил, но все еще интересно
Дейв Хиллиер