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


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.