Як визначити, що має отримати власний контролер?


10

Я використовую шаблон MVC у своєму веб-додатку, створеному за допомогою PHP.

Я завжди намагаюся визначити, чи потрібен мені новий виділений контролер для набору дій, чи потрібно розміщувати їх у вже існуючому контролері.

Чи є якісь хороші правила, які слід дотримуватися при створенні контролерів?

Наприклад, я можу мати:

AuthenticationController з діями:

  • index() для відображення форми входу.
  • submit() обробляти подання форми.
  • logout(), роз'яснення.

АБО

LoginController з діями:

  • index() для відображення форми входу.
  • submit() обробляти подання форми.

LogoutController з дією:

  • index() обробляти вихід із системи.

АБО

AccountController з діями:

  • loginGet() для відображення форми входу.
  • loginPost() обробляти подання форми для входу.
  • logoutGet() обробляти вихід із системи.
  • registerGet() відобразити реєстраційну форму.
  • registerPost() обробляти подання форми.

    І будь-які інші дії, пов’язані з обліковим записом.


Можливо, подивіться на RESTful дизайн. Це не вирішує будь-яку подібну проблему, але дає дуже хороший напрямок, як думати про це.
thorsten müller

Відповіді:


3

Для того, щоб знайти правильну групу для контролерів, продумайте тестування .

(Навіть якщо ви насправді не проводите тестування, думка про те, як би ви йшли на тестування своїх контролерів, дасть вам дуже гарну думку про те, як їх структурувати.)

AuthenticationControllerЧи не перевіряються сам по собі, тому що він містить тільки функціональні можливості для входу в систему і виходу з системи , але ваш код тестування потрібно буде якимось - то чином створити підроблені облікові записи для цілей тестування , перш ніж він може перевірити успішну реєстрацію. Ви можете обійти підтесту підтесту та перейти безпосередньо до своєї моделі для створення тестових облікових записів, але тоді у вас буде крихкий тест: якщо модель зміниться, вам доведеться змінювати не тільки код, які тести модель, а також код, який тестує контролер, навіть якщо інтерфейс та поведінка контролера залишилися незмінними. Це нерозумно.

A LoginControllerнепридатний з тих же причин: ви не можете перевірити його без створення облікових записів спочатку, і ще більше речей, які ви не можете перевірити, як-от, наприклад, запобігання повторюваних входів, але потім дозволяєте користувачеві входити після виходу з системи. (Оскільки цей контролер не має функцій виходу.)

AccountControllerДасть вам все , що потрібно для того , щоб зробити ваше тестування: ви можете створити тестовий аккаунт , а потім спробувати авторизації, Ви можете видалити обліковий запис , а потім переконайтеся , що ви не можете Ввійти більше, ви можете змінити пароль і переконайтеся , що для входу в систему потрібно використовувати правильний пароль.

На закінчення: щоб написати навіть найменший тестовий набір, вам потрібно буде забезпечити AccountControllerдоступність усієї функціональності . Підрозділення його на менші контролери, здається, дає неповносправні контролери з недостатньою функціональністю для належного тесту. Це дуже хороший показник того, що функціональність AccountControllerє найменшим підрозділом, який має сенс.

І взагалі кажучи, підхід "подумай про тестування" працюватиме не тільки в цьому конкретному сценарії, але і в будь-якому подібному сценарії, який ти зустрінеш у майбутньому.


1

Відповідь не така очевидна

Будь ласка, дозвольте мені уточнити кілька речей, перш ніж я буду робити відповіді. Поперше:

Що таке контролер?

Контролер - це частина системи, яка контролює запит - після відправки. Таким чином, ми можемо визначити це як деякий набір дій, пов’язаних із ... що?

Яка сфера застосування контролера?

І це більш-менш частина, коли ми будемо мати будь-яку відповідь. Як ти гадаєш? Це контролер речей (наприклад, Рахунку) чи контролер дій? Звичайно, це контролер якоїсь моделі або якась більш абстрактна річ, яка забезпечує дії над нею.

Відповідь ...

AuthenticationController з діями:

  • index () для відображення форми входу.
  • submit () обробляти подання форми.
  • вихід (), роз'яснення.

Так, автентифікація - це процес. Не йдіть таким шляхом.

Контролер входу з діями:

  • index () для відображення форми входу.
  • submit () обробляти подання форми.

Те ж саме. Вхід - дія. Краще не створюйте контролер дій (у вас немає моделі, що відповідає йому).

AccountController з діями:

  • loginGet () для відображення форми входу.
  • loginPost () для обробки подання форми для входу.
  • logoutGet () для обробки виходу з системи.
  • registerGet () для відображення реєстраційної форми.
  • registerPost () для обробки подання форми.

Дуже добре, але я не переконаний, що побудувати цей контролер низького рівня (контролер - це абстракція) варто довести. У всякому разі, створення методів за допомогою * Get або * Post незрозуміло.

Будь-яка пропозиція?

Так, врахуйте:

AccountController:

  • вхід (AccountModel)
  • вихід (AccountModel)
  • зареєструватися (AccountModel)
  • індекс ()

І пов'язана з ним модель, ofc клас рахунку. Це дасть вам можливість перемістити пару моделей-контролерів кудись інше (якщо це буде потрібно) і зробити чіткий код (очевидно, що login()означає метод). Вражання до моделі справді відоме, особливо з додатками CRUD, і, можливо, це спосіб для вас.


1

Контролери зазвичай створюються для певного ресурсу (клас сутності, таблиця в базі даних), але також можуть бути створені для групування дій, відповідальних за певну частину програми. У ваших прикладах це контролер aa, який обробляє безпеку для програми:

class SecurityController
{
    // can handle both the login page display and
    // the login page submission
    login(); 

    logout();

    register();

    // optional: confirm account after registration
    confirm();

    // displays the forgot password page
    forgotPassword();

    // displays the reset password page
    // and handle the form submission
    resetPassword();
}

Примітка : не ставте дії, пов’язані з безпекою, і дії профілю користувача в один і той же контролер; це може мати сенс, оскільки вони пов’язані з користувачем, але один повинен обробляти автентифікацію, а другий повинен обробляти оновлення електронної пошти, імені тощо.

З контролерами, створеними для ресурсів (скажімо Task), ви мали б звичайні дії CRUD :

class TasksController
{
    // usually displays a paginated list of tasks
    index();

    // displays a certain task, based on an identifier
    show(id);

    // displays page with form and
    // handles form submission for creating
    // new tasks
    create();

    // same as create(), but for changing records
    update(id);     

    // displays confirmation message
    // and handles submissions in case of confirmation
    delete()
}

Звичайно, у вас є можливість додати відповідні ресурси до того ж контролера. Скажімо, наприклад, що у вас є сутність Business, і кожна має кілька BusinessServiceсутностей. Контролер для цього може виглядати приблизно так:

class BusinessController
{
    index();

    show(id);

    create();

    update(id);

    delete();

    // display the business services for a certain business
    listBusinessServices(businessId);

    // displays a certain business service
    showBusinessService(id);

    // create a new business service for a certain business
    createBusinessService(businessId);

    // updates a certain business service
    updateBusinessService(id);

    // deletes a certain business service
    deleteBusinessService(id);
}

Цей підхід має сенс, коли споріднені дитячі сутності не можуть існувати без материнської сутності.

Це мої рекомендації:

  • створити контролери на основі групи пов'язаних операцій (поводження з певними обов'язками, такими як безпека або операції CRUD на ресурсах тощо);
  • для контролерів на основі ресурсів не додайте зайвих дій (якщо ви не повинні оновлювати ресурс, не додайте дії оновлення);
  • Ви можете додати "спеціальні" дії для спрощення речей (наприклад, у вас є Subscriptionоб'єкт, який має доступ на основі обмеженої кількості записів, ви можете додати нову дію до контролера з ім'ям, use()який має єдину мету відняти один запис із Subscription)
  • будьте простими - не захаращуйте контролер величезною кількістю дій та складної логіки, намагайтеся спростити речі, зменшивши кількість дій або зробивши два контролери;
  • якщо ви використовуєте структуру, орієнтовану на MVC, дотримуйтесь їхніх рекомендацій щодо найкращої практики (якщо вони є).

Деякі ресурси для подальшого читання тут .


0

Я бачу дві "сили" антагоністичного дизайну (які не є винятковими для контролерів):

  • згуртованість - контролери повинні групувати пов'язані дії
  • простота - контролери повинні бути якомога меншими, щоб керувати їх складністю

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

Першим моїм інспектом було б групувати вхід та вихід в один контролер. Але якщо реалізація контролера входу та виходу не така проста (наприклад, вхід має captcha, більше методів аутентифікації тощо), я б не мав жодних проблем розділити їх на LoginController та LogoutController для підтримки простоти. Там, де лежить цей поріг складності (коли слід почати розбивати контролер), є дещо особистим.

Також пам’ятайте, що як би ви не розробляли свій код спочатку, ви можете (і повинні) переробити його по мірі зміни. У цьому випадку цілком типово починати з простої конструкції (мати один AuthenticationController), і з часом ви отримаєте більше вимог, які ускладнять код. Після того, як він переступить поріг складності, слід повернути його до двох контролерів.

До речі, ваш код говорить про те, що ви виходите з користувача із запитом GET. Це погана ідея, оскільки HTTP GET повинен бути недійсним (він не повинен змінювати стан програми).


0

Ось кілька правил:

  • Впорядкуйте за темою чи темою, при цьому ім'я контролера має назву теми.

  • Пам’ятайте, що ім'я контролера відображатиметься в URL-адресі, видимій вашим користувачам, тому бажано, щоб вони мали сенс.

У ситуації, про яку ви згадуєте (автентифікація), команда MVC вже написала контролер для вас. Відкрийте Visual Studio 2013 і натисніть кнопку

File / New / Project... 
Search installed templates for "ASP.NET MVC4 Web Application"
Choose "Internet Application" / OK.

AccountController.cs містить усі методи управління обліковими записами користувачів:

Login()
Logoff()
Register()
Disassociate()
Manage()
ExternalLogin()

Так вони організовані за темою "Облікові записи користувачів та автентифікація", із видимою назвою теми "Обліковий запис".


0

Термінологія

Я вважаю, що називати клас "контролером" класом, який містить деякі HTTP-методи, є великою помилкою.

Контролер - це метод, який обробляє запит, але не клас, що містить такі методи . Так index(), submit(), logout()є контролерами.

Клас, що містить такий тип методів, називається "контролер" лише тому, що він складається з групи контролерів і відіграє роль простору імен "нижнього рівня". Мовою FP (як Haskell) це був би просто модуль. Доцільно зберігати класи "контролера" якомога більше без громадян у мовах OOP, за винятком посилань на сервіси та інші програмні програми.

Відповідь

З термінологічним впорядкованим питанням виникає питання "як слід розділяти контролери на простори / модулі імен?" Я думаю, що відповідь полягає в тому, що контролери всередині одного простору імен / модуля повинні працювати з тими ж даними . Наприклад, UserControllerстосується в основному випадків Userкласу, але час від часу торкається інших пов'язаних речей, якщо потрібно.

Так login, logoutі інші подібні дії, в основному справу з сесією, він , ймовірно , найкраще помістити їх усередину SessionController, і indexконтролер, який просто виводить форму, повинен бути поміщений в LoginPageController, так як він , очевидно , має справу з сторінкою входу. Мало сенсу розміщувати HTML-рендерінг та управління сеансами в один клас, і це порушить SRP і, можливо, купу інших хороших практик.

Загальний принцип

Коли у вас виникають проблеми вирішити, куди вкласти фрагмент коду, почніть з даних (та типів), з якими ви маєте справу.


2
Вибачте, це дії, а не контролери :)
JK01

@ JK01 Це те, що ти їх називаєш. Це термінологія, знаєте. І є рамки, які називають ці функції "контролерами" (або "обробниками"), оскільки існує багато фреймів, які не впорядковують їх у класи, оскільки просторів імен / модулів вже достатньо. Ви можете використовувати будь-які терміни, які вам подобаються, це просто слова, але я думаю, що менше термінів - це краще.
сценарій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.