Адкрыты / Закрыты, паводле прынцыпу ТВАРДЫ

адкрыты закрыты прынцып
метады

Суб'екты праграмнага забеспячэння (класы, модулі, функцыі і г.д.) павінны быць адкрыты для пашырэння, але закрыты для рэдагавання.

Распрацоўка праграмнага забеспячэння: модуляў, класаў і функцый такім чынам, каб пры неабходнасці новых функцый мы не павінны мадыфікаваць існуючы код, а пісаць новы код, які будзе выкарыстоўвацца існуючым кодам. Гэта можа здацца дзіўным, асабліва з такімі мовамі, як Java, C, C ++ або C #, дзе гэта адносіцца не толькі да самага зыходнага кода, але і да двайковага файла. Мы хочам стварыць новыя функцыі спосабамі, якія не патрабуюць пераразмеркавання існуючых бінарных файлаў, выкананых файлаў альбо DLL-файлаў.
OCP у цвёрдым кантэксце

 

SRP і OCP дапаўняюць адзін аднаго

Мы ўжо бачылі прынцып SRP адзінай адказнасці, які сцвярджае, што модуль павінен мець толькі адну прычыну для змены. Прынцыпы OCP і SRP дапаўняюць адзін аднаго. Код, распрацаваны ў адпаведнасці з прынцыпам SRP, таксама будзе паважаць прынцыпы OCP. Калі ў нас ёсць код, у якога ёсць толькі адна прычына для змены, увядзенне новай функцыі створыць другасную прычыну гэтага змены. Такім чынам, SRP і OCP будуць парушаныя. Сапраўды гэтак жа, калі ў нас ёсць код, які павінен змяняцца толькі пры змене яго асноўнай функцыі і павінен заставацца нязменным пры даданні новай функцыянальнасці, паважаючы, такім чынам, OCP, ён у асноўным будзе паважаць і SRP.
Гэта не азначае, што SRP заўсёды вядзе да OCP альбо наадварот, але ў большасці выпадкаў, калі прытрымліваецца аднаго з іх, дамагчыся другога даволі проста.

 

Прыклад парушэння прынцыпу OCP

З чыста тэхнічнага пункту гледжання адкрыты / закрыты прынцып вельмі просты. Простая сувязь паміж двума класамі, як прыведзеная ніжэй, парушае прынцып OCP.

логіка карыстальніка ocp

Клас User выкарыстоўвае непасрэдна клас Logic. Калі нам трэба рэалізаваць другі клас Logic такім чынам, каб мы маглі выкарыстоўваць як бягучы, так і новы, існуючы клас Logic трэба будзе змяніць. Карыстальнік непасрэдна прывязаны да рэалізацыі логікі, мы не можам даць новую логіку, не закранаючы бягучую. І калі мы гаворым пра статычна набраныя мовы, клас User, верагодна, таксама патрабуе мадыфікацый. Калі мы гаворым пра скампіляваныя мовы, безумоўна, і выканальны файл карыстальніка, і выканальны файл Logic, альбо дынамічная бібліятэка патрабуюць перакампіляцыі і дастаўкі, пераважна пазбягаць, калі гэта магчыма.

Спасылаючыся на папярэднюю схему, мы можам зрабіць выснову, што любы клас, які непасрэдна выкарыстоўвае іншы клас, можа прывесці да парушэння прынцыпу Open / Closed. 
Дапусцім, мы хочам напісаць клас, здольны забяспечыць прагрэс "у працэнтах" загружанага файла праз наша дадатак. У нас будзе два асноўныя класы, "Прагрэс" і "Файл", і я мяркую, што мы хацелі б выкарыстоўваць іх наступным чынам:

 

функцыя testItCanGetTheProgressOfAFileAsAPercent () {
     $ файл = новы файл ();
     $ файл-> даўжыня = 200;
     $ файл-> адпраўлены = 100;
     $ progress = новы прагрэс ($ файл);
     $ this-> assertEquals (50, $ progress-> getAsPercent ());
}

У гэтым кодзе мы - карыстальнікі Progress. Мы хочам атрымаць значэнне ў працэнтах, незалежна ад фактычнага памеру файла. Мы выкарыстоўваем файл у якасці крыніцы інфармацыі. Файл мае даўжыню ў байтах і поле, якое называецца адпраўленым, якое ўяўляе аб'ём дадзеных, адпраўленых загрузніку. Нам усё роўна, як гэтыя значэнні абнаўляюцца ў дадатку. Мы можам выказаць здагадку, што для нас гэта робіцца нейкая магічная логіка, таму ў тэсце мы можам іх дакладна ўсталяваць.

 

class File {
     дзяржаўная даўжыня $;
     грамадскі $ адпраўлены;
}

 

Клас File - гэта проста просты аб'ект дадзеных, які змяшчае два поля. Зразумела, ён таксама павінен утрымліваць іншую інфармацыю і паводзіны, напрыклад, імя файла, шлях, адносны шлях, бягучы каталог, тып, дазволы і г.д.

 

прагрэс класа {

     прыватны $ файл;

     функцыя __construct (Файл $ файл) {
          $ this-> файл = $ файл;
     }

     функцыя getAsPercent () {
          вярнуць $ this-> файл-> адпраўлены * 100 / $ this-> файл-> даўжыня;
     }

}

Прагрэс - гэта проста клас, які прымае файл у сваім канструктары. Для нагляднасці мы ўказалі тып зменнай у параметрах канструктара. У Progress існуе адзіны карысны метад, getAsPercent (), які прымае адпраўленыя значэнні і даўжыню з файла і ператварае іх у працэнты. Проста, і гэта працуе.

Здаецца, гэты код правільны, аднак ён парушае прынцып Адкрыта / Закрыта.

Але чаму?

І як?

 

Паспрабуем змяніць патрабаванні

Кожнаму дадатку, каб развівацца з цягам часу, спатрэбяцца новыя функцыі. Новай функцыяй нашага прыкладання можа стаць дазвол струменевай перадачы музыкі, а не проста загрузка файлаў. Даўжыня файла прадстаўлена ў байтах, працягласць музыкі ў секундах. Мы хочам прапанаваць слухачам прагрэс, але ці можам мы паўторна выкарыстаць напісаны вышэй клас?

Не, мы не можам. Наш прагрэс звязаны з File. Ён можа кіраваць толькі інфармацыяй пра файлы, хоць ён таксама можа прымяняцца да музычнага кантэнту. Але для гэтага нам трэба яе змяніць, мы павінны зрабіць так, каб Progress ведаў музыку і файлы. Калі б наш дызайн адпавядаў OCP, нам не трэба было б дакранацца да File або Progress. Мы маглі б проста выкарыстаць існуючы прагрэс і прымяніць яго да музыкі.

 

Магчымае рашэнне

Дынамічна набіраныя мовы маюць перавагу ў кіраванні тыпамі аб'ектаў падчас выканання. Гэта дазваляе нам выдаліць падказку з канструктара Progress, і код будзе працягваць працаваць.

прагрэс класа {

     прыватны $ файл;

     функцыя __construct ($ файл) {
         $ this-> файл = $ файл;
     }

    функцыя getAsPercent () {
         вярнуць $ this-> файл-> адпраўлены * 100 / $ this-> файл-> даўжыня;
     }

}

Цяпер мы можам запусціць што заўгодна ў Progress. І пад любым словам я маю на ўвазе літаральна ўсё:

клас Музыка {

дзяржаўная даўжыня $;
грамадскі $ адпраўлены;

публічны $ мастак;
публічны $ альбом;
грамадскі $ releaseDate;

функцыя getAlbumCoverFile () {
return 'Выявы / Вокладкі /'. $ this-> мастак. '/'. $ this-> альбом. '.png';
}
}

І такі клас музыкі будзе працаваць выдатна. Мы можам лёгка праверыць яго тэстам, вельмі падобным на File.
функцыя testItCanGetTheProgressOfAMusicStreamAsAPercent () {
$ music = новая музыка ();
$ музыка-> даўжыня = 200;
$ музыка-> адпраўлена = 100;

$ progress = новы прагрэс ($ музыка);

$ this-> assertEquals (50, $ progress-> getAsPercent ());
}

Такім чынам, у асноўным любы вымяраемы змест можна выкарыстоўваць з класам Progress. Магчыма, нам варта выказаць гэта ў кодзе, таксама змяніўшы імя зменнай:

прагрэс класа {

прыватны $ вымяральны кантэнт;

функцыя __construct ($ mjerljiviContent) {
$ this-> измеримыйКонтент = $ измеримыйКонтент;
}

функцыя getAsPercent () {
вярнуць $ this-> измеримыйКонтент-> адпраўлены * 100 / $ гэты-> вымяральныКонтэнт-> даўжыня;
}

}

Калі мы ўказалі File у якасці падказкі, мы з аптымізмам глядзелі на тое, што наш клас можа апрацаваць. Гэта было відавочна, і калі б што-небудзь яшчэ прыйшло, нам паведамілі б вялікую памылку.

Uклас, які перавызначае метад базавага класа, так што кантракт базавага класа не выконваецца вытворным класам. 

Мы не хочам у канчатковым выніку спрабаваць выклікаць метады альбо адкрыць палі для аб'ектаў, якія не адпавядаюць нашаму кантракту. Калі ў нас быў падказка, ім быў указаны кантракт. Поля і метады класа File. Цяпер у нас нічога няма, мы можам адправіць што заўгодна, нават радок, і гэта прывядзе да дрэннай памылкі.

У той час як канчатковы вынік у любым выпадку аднолькавы, што азначае, што код ламаецца, першы вывеў добрае паведамленне. Аднак гэта вельмі незразумела. Немагчыма даведацца, што такое зменная - у нашым выпадку радок - і якія ўласцівасці шукалі, а не знайшлі. Цяжка адладзіць і выправіць праблему. Праграмісту трэба адкрыць клас Progress, прачытаць яго і зразумець. У гэтым выпадку кантракт, калі падказка тыпу дакладна не ўказана, вызначаецца паводзінамі Progress. Гэта падразумяваецца кантракт, вядомы толькі "Прагрэсу". У нашым прыкладзе ён вызначаецца шляхам доступу да двух палёў, пасланага і даўжыні, у метадзе getAsPercent (). У рэальным жыцці няяўны кантракт можа быць вельмі складаным і складаным для выяўлення, проста пашукаўшы некалькі секунд у класе.

Гэта рашэнне рэкамендуецца толькі ў тым выпадку, калі ні адзін з апісаных ніжэй парад не можа быць лёгка рэалізаваны альбо калі яны ўнясуць сур'ёзныя архітэктурныя змены, якія не патрабуюць высілкаў.

Эрколе Палмеры

CV Эрколе Палмеры
Каментаваць няма

пакінуць каментар

Il Tuo indirizzo электроннай пошты ня sarà pubblicato. Я Кампа Соно obbligatori contrassegnati *

стратэгія бізнес-аналітыкі
метады
Стратэгіі паспяховай бізнес-аналітыкі

Стварэнне паспяховай стратэгіі для вашай бізнес-аналітыкі пачынаецца з правільнага бачання мэтаў. Ніжэй мы бачым некаторыя асноўныя моманты. Ацэнка бягучай сітуацыі Было б сур'ёзнай памылкай недаацэньваць гэты аспект. Ацэнка бягучай сітуацыі азначае аналіз працэсаў, структур ...

Цвёрдыя цвёрдыя геаметрычныя фігуры
навучанне
1
SOLID, якія 5 прынцыпаў аб'ектна-арыентаванага праграмавання

SOLID - гэта абрэвіятура, якая спасылаецца на пяць прынцыпаў аб'ектна-арыентаванага дызайну (OOD або OOP). Гэта рэкамендацыі, якія распрацоўшчыкі могуць выкарыстоўваць для стварэння праграмнага забеспячэння, якое лёгка кіраваць, падтрымліваць і пашыраць. Разуменне гэтых паняццяў зробіць вас лепшым распрацоўшчыкам і дазволіць ...

сэнс новаўвядзення
метады
4 (практычныя) этапы стварэння новаўвядзення

Не сакрэт: пандэмія каранавірусу змяніла жыццё многіх людзей. З дня ў дзень мы заставаліся без працы альбо проста з неабходнасцю зрабіць нешта новае, даць жыццё інавацыі. У гэтым артыкуле мы хочам дапамагчы вам, рэкамендаваўшы 4 простыя крокі, каб даць ...