Көз карандылык инъекциясы (DI) түшүнүү оңой түшүнүк эмес жана аны жаңы же учурдагы тиркемелерге колдонуу ого бетер чаташып турат. Джесс Смит C# жана Java программалоо тилдеринде инъекциялык контейнерсиз көз карандылык инъекциясын кантип жасоону көрсөтөт. Бул макалада мен .NET жана Java тиркемелеринде көз карандылык инъекциясын (DI) кантип ишке ашырууну көрсөтөм. Көз карандылык инъекциясы түшүнүгү биринчи жолу иштеп чыгуучулардын көңүлүн 2000-жылы Роберт Мартин "Дизайн принциптери жана үлгүлөрү" (кийин
SOLID кыскартуусу менен белгилүү болгон ) макаласын жазганда бурган. SOLIDдеги D кийинчерээк көз карандылык инъекциясы катары белгилүү болгон Инversionнын көз карандылыгына (DOI) тиешелүү. Түпнуска жана эң кеңири таралган аныктама: көз карандылыктын инversionсы – бул базалык класстын көз карандылыкты башкаруу ыкмасынын инversionсы.
Copy
Мартиндин оригиналдуу макаласында класстын төмөнкү деңгээлдеги класска көз карандылыгын көрсөтүү үчүн төмөнкү code колдонулган
WritePrinter
:
void Copy()
{
int c;
while ((c = ReadKeyboard()) != EOF)
WritePrinter(c);
}
Биринчи айкын көйгөй, эгерде сиз параметр тизмесин же методдун түрлөрүн өзгөртсөңүз
WritePrinter
, анда ал ыкмага көз карандылык бар жерде жаңыртууларды ишке ашыруу керек. Бул процесс техникалык тейлөөгө кеткен чыгымдарды көбөйтөт жана жаңы каталардын потенциалдуу булагы болуп саналат.
Дагы бир көйгөй: Көчүрмө классы кайра колдонуу үчүн потенциалдуу талапкер болбой калды. Мисалы, клавиатурадан киргизилген символдорду принтерге эмес, файлга чыгаруу керек болсочы? Бул үчүн классты
Copy
төмөнкүдөй өзгөртө аласыз (C++ тorнин синтаксиси):
void Copy(outputDevice dev)
{
int c;
while ((c = ReadKeyboard()) != EOF)
if (dev == printer)
WritePrinter(c);
else
WriteDisk(c);
}
Жаңы көз карандылык киргизилгенине карабастан
WriteDisk
, кырдаал жакшырган жок (тескерисинче начарлап кетти), анткени дагы бир принцип бузулду: “программалык камсыздоо an objectилери, башкача айтканда класстар, модулдар, функциялар жана башкалар кеңейтүү үчүн ачык болушу керек, бирок алар үчүн жабык болушу керек. өзгөртүү." Мартин бул жаңы шарттуу if/else билдирүүлөрү codeдун туруктуулугун жана ийкемдүүлүгүн азайтат деп түшүндүрөт. Чечим көз карандылыктарды инversionлоо болуп саналат, ошондуктан жазуу жана окуу ыкмалары
Copy
. Көз карандылыктын "поп" ордуна, алар конструктор аркылуу өткөрүлөт. Өзгөртүлгөн code төмөнкүдөй көрүнөт:
class Reader
{
public:
virtual int Read() = 0;
};
class Writer
{
public:
virtual void Write(char) = 0;
};
void Copy(Reader& r, Writer& w)
{
int c;
while((c=r.Read()) != EOF)
w.Write(c);
}
Эми классты
Copy
класстык методдордун
Reader
жана
Writer
. Класста
Copy
типтердин ички түзүмү жөнүндө эч кандай маалымат жок
Reader
,
Writer
бул аларды ар кандай ишке ашыруулар менен кайра колдонууга мүмкүндүк берет. Бирок, мунун баары сизге кандайдыр бир gobbledygook сыяктуу көрүнсө, балким, Java жана C# тилдериндеги төмөнкү мисалдар кырдаалды түшүндүрөт.
Java жана C# тилдериндеги мисал
DI
Көз карандылык контейнери жок көз карандылык инъекциясынын оңойлугун көрсөтүү үчүн, келгиле , бир нече кадам менен колдонууга ылайыкташтырылган жөнөкөй мисалдан баштайлы . Бизде класс бар дейли
HtmlUserPresentation
, анын методдору чакырылганда HTML колдонуучу интерфейсин жаратат. Бул жерде жөнөкөй мисал:
HtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
Бул класстын codeун колдонгон ар бир долбоор класска көз каранды болот
HtmlUserPresentation
, натыйжада жогоруда сүрөттөлгөн колдонууга жана тейлөөгө жөндөмдүүлүк маселелери пайда болот. Жакшыртуу дароо эле өзүн сунуштайт: класста жеткorктүү болгон бардык ыкмалардын кол тамгалары менен интерфейс түзүү
HtmlUserPresentation
. Бул интерфейстин мисалы:
public interface IHtmlUserPresentation {
String createTable(ArrayList rowVals, String caption);
String createTableRow(String tableCol);
}
Интерфейс түзүлгөндөн кийин
HtmlUserPresentation
аны колдонуу үчүн классты өзгөртөбүз. Типти баштоого кайрылып
HtmlUserPresentation
, биз эми базалык типтин ордуна интерфейс түрүн колдоно алабыз:
IHtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
Интерфейс түзүү бизге башка ишке ашырууларды оңой колдонууга мүмкүндүк берет
IHtmlUserPresentation
. Мисалы, эгер биз бул түрдү сынагыбыз келсе, анда биз базалык түрдү
HtmlUserPresentation
башка түргө алмаштыра алабыз
HtmlUserPresentationTest
. Буга чейин киргизилген өзгөртүүлөр codeду текшерүүнү, тейлөөнү жана масштабын жеңилдетет, бирок кайра колдонуу үчүн эч нерсе жасаbyte, анткени
HtmlUserPresentation
түрүн колдонгон бардык класстар анын бар экенин дагы эле бorшет. Бул түздөн-түз көз карандылыкты алып салуу үчүн, сиз интерфейстин түрүн
IHtmlUserPresentation
аны колдоно турган класстын же методдун конструкторуна (же метод параметрлеринин тизмесине) өткөрүп берсеңиз болот:
public UploadFile(IHtmlUserPresentation htmlUserPresentation)
Конструктор
UploadFile
эми типтеги бардык функцияларга жетүү мүмкүнчүлүгүнө ээ
IHtmlUserPresentation
, бирок бул интерфейсти ишке ашырган класстын ички түзүмү жөнүндө эч нерсе билбейт. Бул контекстте типти киргизүү класстын үлгүсү түзүлгөндө пайда болот
UploadFile
. Интерфейс түрү
IHtmlUserPresentation
ар кандай ишке ашырууларды ар кандай класстарга же башка функцияларды талап кылган методдорго өткөрүү менен кайра колдонууга болот.
Корутунду жана материалды консолидациялоо боюнча сунуштар
Сиз көз карандылык инъекциясы жөнүндө билдиңиз жана класстар бири-бирине түздөн-түз көз каранды деп айтылат, эгерде алардын бири экинчисин максаттуу түрдөгү функцияга жетүү үчүн ишке киргизет. Эки түрдүн ортосундагы түз көз карандылыкты ажыратуу үчүн интерфейсти түзүшүңүз керек. Интерфейс типке талап кылынган функциянын контекстине жараша ар кандай ишке ашырууларды камтуу мүмкүнчүлүгүн берет. Интерфейс түрүн класстын конструкторуна же методуна өткөрүп берүү менен, функционалдуулукка муктаж класс/усул интерфейсти ишке ашыруучу тип жөнүндө эч кандай деталдарды билбейт. Ушундан улам, интерфейстин түрү окшош, бирок бирдей эмес жүрүм-турумду талап кылган ар кандай класстарда кайра колдонулушу мүмкүн.
- Көз карандылык инъекциясын эксперимент кылуу үчүн, бир же бир нече тиркемелерден codeуңузду карап чыгып, көп колдонулган базалык типти интерфейске айландырууга аракет кылыңыз.
- Бул жаңы интерфейс түрүн колдонуу үчүн бул базалык типти түздөн-түз түзүүчү класстарды өзгөртүңүз жана аны конструктор же аны колдоно турган класс методунун параметр тизмеси аркылуу өткөрүңүз.
- Бул интерфейс түрүн сыноо үчүн сыноо ишке ашырууну түзүңүз. Кодуңуз рефакторациялангандан кийин,
DI
аны ишке ашыруу оңой болуп калат жана колдонмоңуз кайра колдонуу жана тейлөө жагынан канчалык ийкемдүү болуп калганын байкайсыз.
GO TO FULL VERSION