Що означає вводити дані (проти поведінки) в конструктор класу, і чому це вважається поганою практикою?


10

Я читаю книгу "Навчання TypeScript" Ремо Янсена. В одному з розділів автор описує, як створити дуже просту рамку MVC з підтвердженням концепції, включаючи, як створити Modelклас, і говорить наступне:

Модель має бути забезпечена URL-адресою веб-сервісу, який вона споживає. Ми будемо використовувати декоратор класу під назвою ModelSettings для встановлення URL-адреси служби, яка буде споживатися. Ми могли б ввести URL-адресу служби через її конструктор, але вважається поганою практикою введення даних (на відміну від поведінки) через конструктор класів .

Я не розумію цього останнього речення. Зокрема, я не розумію, що означає "вводити дані". Мені здається, що майже у всіх знайомствах з класами JavaScript, використовуючи надто спрощені приклади, в конструктор вводяться («вводяться»?) Через його параметри. Наприклад:

class Person {
  constructor(name) {
    this.name = name;
  }
}

Я, безумовно, вважаю nameце даними, а не поведінкою, і він є загальноприйнятим у цьому прикладі як параметр конструктора, і ніколи не згадується, що це погана практика. Таким чином, я припускаю, що я розумію щось у наведеній цитаті, або те, що розуміється під "даними", або "введенням", або щось інше.

Ваші відповіді можуть містити пояснення, коли, де, як і навіщо використовувати декоратори в JavaScript / TypeScript, оскільки я дуже підозрюю, що ця концепція тісно пов'язана з розумінням, яке я прагну. Однак, що ще важливіше, я хочу зрозуміти більш загально, що розуміється під введенням даних через конструктор класів і чому це погано.


Щоб надати більше контексту вищенаведеній цитаті, така ситуація: створюється Modelклас, який у цьому прикладі буде використовуватися для створення біржових моделей, один для NASDAQ і один для NYSE. Кожна модель вимагає шляху веб-служби або статичного файлу даних, який надаватиме необроблені дані. У книзі зазначено, що для цієї інформації слід використовувати декоратор, а не параметр конструктора, що призводить до наступного:

@ModelSettings("./data/nasdaq.json")
class NasdaqModel extends Model implements IModel {
  constructor(metiator : IMediator) {
    super(metiator);
  }
...
}

Я просто не розумів, чому я повинен додавати службовий URL через декоратор, а не просто як параметр для конструктора, наприклад

constructor(metiator : IMediator, serviceUrl : string) {...

Я б запропонував вам зробити швидкий пошук в Google щодо ін'єкції залежності . Це не правильний форум, щоб задати це питання. :)
toskv

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

Введення залежності та введення даних - це дві різні речі. 1-й - принцип дизайну, а другий - тип атаки. Якщо ви хочете чіткіше пошуковий термін, спробуйте "інверсія управління". Це трохи ширше, але також допомагає намалювати більш чітку картину.
toskv

1
Нападки "введення даних" - це, на мою думку, зовсім інша тварина, про що говорить автор книги, котрий цитує, коли каже "вводити дані". Це одна з причин, коли я був розчарований пошуками Google щодо цього. Навіть якщо мені потрібно зрозуміти, наприклад, принципи SOLID краще, я не розумію, як надання "імені" в якості параметра конструктору "Person" є нормальним і нормальним, але надання "serviceUrl" в якості параметра для "Моделі" конструктор невідповідний, або чим він навіть відрізняється від прикладу "ім'я" / "особа".

7
Я думаю, що Ремо помиляється. Параметри - це дані, незалежно від того, що він каже. Дані, які вводяться завжди, мають тип, і всі типи об'єктно-орієнтованих мов мають певну поведінку.
Роберт Харві

Відповіді:


5

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

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

Якщо конкретний клас залежить від конкретного фрагмента даних для того, щоб він був у дійсному стані та працював належним чином, має сенс вимагати цих даних у конструкторі. Клас, що представляє послідовний порт, може приймати ім'я порту, об’єкт файлу може вимагати ім'я файлу, полотно малювання, яке вимагає його роздільної здатності тощо. Якщо ви не передасте дані в конструктор, можливо, ви могли б мати об'єкт у недійсному стані, що має спостерігати і перевіряти. В іншому випадку ви можете перевірити лише об'єкт, і здебільшого припустити його функціонування здебільшого. Автори стверджують, що вигідна ситуація неможлива.

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

Навіть якщо змінні об'єкти - це те, що ви хочете, як це погана практика:

var blah = new Rectangle(x,y,width,height);

на користь:

var blah = new Rectangle();
blah.X = x;
blah.Y = y;
blah.Width = width;
blah.Height = height;

Чи справді автор вважає, що перша - це погана практика, і я завжди повинен відповідати варіанту 2? Я думаю, що це шалені розмови.

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


Дуже дякую за вашу дискусію. Те, що ви говорите, «пахне мені», особливо коли ви наводите приклад прямокутника. Мені все ще цікаво, чи автор розрізняє дані, необхідні для класу, порівняно з кожним екземпляром класу. Однак я не думаю, що проект, який описується у книзі, дійсно не надто глибокий, щоб уточнити це. Як зауваження, ваша відповідь надіслала мене на первинному дослідженні незмінності об'єкта, як би це не було чи не стосується мого початкового запитання, тож спасибі за це!
Ендрю Віллемс

0

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

Сервіс без громадянства має ряд переваг, наприклад, кожен, хто читає виклик методу обслуговування, не потребує пошуку, коли служба побудована, щоб дізнатись деталі викликаної послуги. Усі деталі відображаються в аргументах, що використовуються у виклику методу (крім віддаленого URL-адреси).


Так, модель потребує отримання даних (зрештою, з віддаленого веб-сервісу, як ви пропонуєте, але в книзі це лише демонстрація, тому спочатку просто знущаються над даними, кодованими безпосередньо в рядку). Я не розумію вашої пропозиції щодо передачі даних як аргументів "методами веб-служби". Я питав про розмежування передачі даних як параметрів (1) для конструктора від (2) для декоратора. Здається, ви пропонуєте 3-й варіант, тобто передачу даних як параметрів / аргументів для методу веб-служби. Я пропускаю вашу думку?
Ендрю Віллемс

0

Просто здогадуюсь.

Якщо я прислухаюся до "поведінки ін'єкцій, а не до даних", я б подумав, а не робити це:

(Вибачте за приклад у псевдокоді):

class NoiseMaker{
  String noise;
  NoiseMaker(String noise){
     this.noise = noise;
  }
  void soNoise(){
    writeToOutput(noise)
  }
}

Зробити це:

interface Noise{
  String getAudibleNoise();
}

class PanicYell implements Noise{
   String getAudibleNoise(){
       return generateRandomYell();
   }
   .....
}



class WhiteNoise implements Noise{
   String getAudibleNoise(){
       return generateNoiseAtAllFrequences();
   }
   .....
}

class NoiseMaker{
  Noise noise;
  NoiseMaker(Noise noise){
     this.noise = noise;
  }
  void soNoise(){
    writeToOutput(noise.getAudibleNoise())
  }
}

Таким чином ви завжди можете змінити поведінку шуму, зробити його випадковим, залежним від однієї внутрішньої змінної ...

Я думаю, що це все в правилі "користь композиції над успадкуванням". Я мушу сказати, що це чудове правило.

Це НЕ означає, що ви не можете "ввести" ім'я об'єкту "Особа", очевидно, тому що це ім'я суто ділові дані. Але у прикладі, який ви надаєте, веб-сервіс, URL-адреса - це те, що вам потрібно, щоб генерувати щось якось, що з'єднує послугу. Це якось є поведінкою: якщо ви вводите URL-адресу, ви вводите "дані", необхідні для побудови "поведінки", тож у такому випадку краще зробити поведінку зовні і ввести її готовою до використання: Натомість введіть URL-адресу користувальницьке з'єднання або придатний конструктор з'єднань.

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