Чи є методом "запуск", "запуск" чи "виконання" хорошою практикою?


30

Зараз я працюю над кодовою базою, в якій є багато класів, які реалізують метод "Старт". Мені це здається двофазним будівництвом, що я завжди вважав поганою практикою. Я не можу сказати різницю між цим та конструктором.

Коли доцільно використовувати метод запуску замість нормальної побудови об'єкта?

Коли я вважаю за краще використовувати конструктор?

Редагувати: Я не думаю, що це актуально, але мова програмування - це 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()методу. Якщо це лише додатковий спосіб встановити більше параметрів, він не повинен існувати.


1
Ще одне використання методу запуску - це коли виконана дія також створює новий робочий потік або таймер. Конструктор не повинен здійснювати подібні важкі підйоми або створювати значні побічні ефекти (наприклад, створення нової нитки).
Ziv

50

Code Complete (та багато інших ресурсів програмного забезпечення) підкреслює відповідність ваших класів об'єктам реального світу. Я вважаю, що основна причина цього полягає в тому, що це робить більш імовірним розуміння того, що ви реалізуєте, а не злому нематеріальної ідеї.

Якщо ви абонент цієї теорії, я не бачу нічого поганого в тому, Start()щоб додати метод до будь-якого класу, який повинен був би бути реальним об'єктом, а також мати стан спокою. Якщо ваш об’єкт не має сенсу існувати під час його запуску (або зовсім не має сенсу, щоб ваш об’єкт працював), то я б сказав, що це погана практика.


16
Хороша аналогія. Варто зазначити, що це Start()може відповідати або перемикачу включення / вимкнення (як світлодіодний перемикач), який тоді повинен мати Stop()клавішу a , або кнопці (як кнопка Друк на копіювальній машині), де він починається, а потім працює до завершення.
Бобсон

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 ти маєш рацію, це не те, про що я просив, але все одно цікаво
Дейв Хіллер,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.