Хамааралтай урвуу байдал. Хараат байдлын урвуу зарчмын шүүмжлэл. Уламжлалт давхаргат архитектур

Үнэндээ бүх зарчим ХАТУУЭдгээр нь хоорондоо нягт холбоотой бөгөөд гол зорилго нь өндөр чанартай, өргөтгөх боломжтой програм хангамжийг бий болгоход туслах явдал юм. Гэхдээ сүүлчийн зарчим ХАТУУүнэхээр тэдний цаанаас ялгардаг. Эхлээд энэ зарчмын томъёололыг харцгаая. Тэгэхээр, хамаарлын урвуу зарчим (Хараат байдлын урвуу зарчим - DIP): “Хийсвэрлэлээс хамаарал. Тодорхой зүйлээс хамаарал байхгүй” гэсэн юм.. Програм хангамжийн хөгжүүлэлтийн чиглэлээр алдартай мэргэжилтэн Роберт Мартин мөн зарчмыг онцолж байна ДҮРЭХбусад зарчмуудыг дагаж мөрдсөний үр дүнд үүнийг энгийнээр харуулж байна ХАТУУ- нээлттэй/хаалттай зарчим ба Лисков орлуулах зарчим. Эхнийх нь шинэ өөрчлөлт оруулахын тулд ангиудыг өөрчлөх ёсгүй, хоёр дахь нь өв залгамжлалтай холбоотой бөгөөд програмын зөв үйл ажиллагаанд саад учруулахгүйгээр зарим үндсэн төрлийн үүсмэл төрлүүдийг аюулгүй ашиглахыг шаарддаг гэдгийг санаарай. Роберт Мартин анх энэ зарчмыг томъёолсон дараах байдлаар:

1). Дээд түвшний модуль нь доод түвшний модулиудаас хамаарах ёсгүй. Хоёр түвшний модулиуд нь хийсвэрлэлээс хамаарах ёстой.

2). Хийсвэрлэл нь нарийн ширийн зүйлээс хамаарах ёсгүй. Дэлгэрэнгүй мэдээлэл нь хийсвэрлэлээс хамаарах ёстой.

Өөрөөр хэлбэл, ангиудыг тодорхой хэрэгжилтийн хувьд бус хийсвэрлэлээр нь хөгжүүлэх хэрэгтэй. Хэрэв та зарчмуудыг дагаж мөрдвөл OCPТэгээд LSP, тэгвэл бид яг ийм зүйлд хүрэх болно. Ингээд хичээл рүүгээ жаахан буцаж орцгооё. Тэнд жишээ болгон бид ангийг авч үзсэн Бард, энэ нь хамгийн эхэнд ангитай хатуу холбоотой байсан Гитар, тодорхой хөгжмийн зэмсгийг төлөөлөх:

нийтийн анги Бард ( хувийн гитар гитар; нийтийн Бард(Гитар гитар) ( this.guitar = гитар; ) public void play() ( guitar.play(); ) )

нийтийн анги Бард (

хувийн гитар гитар;

нийтийн Бард (Гитар гитар)

энэ. гитар = гитар;

нийтийн хүчингүй тоглоом()

гитар тоглох();

Хэрэв бид энэ ангид бусад хөгжмийн зэмсгүүдийн дэмжлэгийг нэмэхийг хүсвэл энэ ангийг ямар нэг байдлаар өөрчлөх хэрэгтэй болно. Энэ бол зарчмыг илт зөрчсөн үйлдэл OCP. Эдгээр нь мөн зарчмын зөрчил гэдгийг та аль хэдийн анзаарсан байх ДҮРЭХ, учир нь бидний хийсвэрлэл нь нарийн ширийн зүйлээс хамааралтай болсон. Манай анги цаашид өргөжин тэлэх үүднээс энэ нь огтхон ч сайн биш юм. Манай анги зарчмын нөхцөлийг хангасан байхаар OCPБид системд интерфэйс нэмсэн Багаж хэрэгсэл, үүнийг тодорхой төрлийн хөгжмийн зэмсгийг төлөөлдөг тусгай ангиуд хэрэгжүүлсэн.

Файл Instrument.java:

нийтийн интерфейсийн хэрэгсэл (void play(); )

нийтийн интерфейсийн хэрэгсэл (

хүчингүй тоглох();

Файл Гитар.жава:

анги Гитар хэрэгжүүлдэг Instrument( @Override public void play() ( System.out.println("Play Guitar!"); ) )

анги Гитар хэрэглүүр Instrument (

@Дараах

нийтийн хүчингүй тоглоом()

Систем. гарч. println("Гитар тогло!");

Файл Lute.java:

public class Lute Instrument-ийг хэрэгжүүлдэг( @Override public void play() ( System.out.println("Play Lute!"); ) )

нийтийн анги Lute хэрэглүүр хэрэгсэл (

@Дараах

нийтийн хүчингүй тоглоом()

Систем. гарч. println("Лут тогло!");

Үүний дараа бид ангиа сольсон Бард, ингэснээр шаардлагатай бол хэрэгжилтийг яг хэрэгтэй зүйлээр сольж болно. Энэ нь үүсгэсэн системд нэмэлт уян хатан байдлыг бий болгож, түүний холболтыг багасгадаг (ангиуд бие биенээсээ хүчтэй хамааралтай).

public class Bard ( private Instrument instrument; public Bard() ( ) public void play() ( instrument.play(); ) public void setInstrument(Instrument instrument) ( this.instrument = instrument; ) )

нийтийн анги Бард (

хувийн багаж хэрэгсэл;

Dependency inversion нь програмчлалын хамгийн чухал хэлц үгсийн нэг юм. Орос хэл дээрх интернетэд энэ хэлц үгийн (зарчмын) тайлбар маш цөөхөн байдаг. Тиймээс би тайлбар хийхээр шийдсэн. Би Java хэл дээр жишээ хийх болно Энэ мөчХараат байдлын урвуу зарчим нь ямар ч програмчлалын хэлэнд хамаатай ч надад илүү хялбар байдаг.

Энэхүү тайлбарыг Владимир Матвеевтэй хамтран Java хэл сурч буй оюутнуудтай хичээлд бэлтгэх зорилгоор боловсруулсан болно.

Энэ цувралын бусад нийтлэлүүд:

Би "донтолт" гэсэн тодорхойлолтоос эхэлье. Донтолт гэж юу вэ? Хэрэв таны код зарим классыг дотооддоо ашигладаг эсвэл зарим класс эсвэл функцын статик аргыг дууддаг бол энэ нь хамаарал юм. Би жишээгээр тайлбарлая:

Доод талд, someMethod() нэртэй аргын доторх А анги нь В ангиллын объектыг тодорхой үүсгэж, түүний аргыг someMethodOfB() гэж дууддаг.

Нийтийн анги А ( хүчингүй болсон someMethod() ( B b = new B(); b.someMethodOfB(); ) )

Үүнтэй адилаар, жишээлбэл, В анги нь Системийн ангийн статик талбарууд болон аргуудад шууд ханддаг:

Нийтийн B анги ( void someMethodOfB() ( System.out.println("Сайн уу ертөнц"); ) )

Аль ч анги (А төрөл) бие даан ямар нэгэн анги (B төрөл) үүсгэх эсвэл статик талбарууд эсвэл ангийн гишүүдэд шууд ханддаг тохиолдолд үүнийг гэнэ. Чигээрээдонтолт. Тэдгээр. чухал: хэрэв доторх анги нь өөр ангитай хамт ажилладаг бол энэ нь хамаарал юм. Хэрэв энэ ангийг өөрөө дотроо үүсгэсэн бол энэ Чигээрээдонтолт.

Шууд хамаарал нь юу нь буруу вэ? Шууд хамаарал нь муу, учир нь бие даан өөр анги үүсгэдэг анги энэ ангитай "нягт" холбогдсон байдаг. Тэдгээр. хэрэв B = new B() гэж тодорхой бичсэн бол; , тэгвэл А анги үргэлж В ангитай ажиллах ба өөр анги байхгүй. Эсвэл System.out.println("..."); Дараа нь анги үргэлж System.out руу гарах ба өөр хаана ч байхгүй.

Жижиг ангиудын хувьд хараат байдал нь аймшигтай биш юм. Энэ код сайн ажиллаж магадгүй. Гэхдээ зарим тохиолдолд таны А анги өөр өөр ангиудын орчинд бүх нийтээр ажиллах чадвартай байхын тулд ангиудын бусад хэрэгжилт - хамаарлыг шаардаж болно. Тэдгээр. Жишээлбэл, танд B анги биш, ижил интерфэйстэй өөр анги хэрэгтэй болно, эсвэл System.out биш, гэхдээ жишээлбэл, бүртгэл хөтлөгч рүү гаргах (жишээ нь log4j).

Шууд хамаарлыг дараах байдлаар графикаар харуулж болно.

Тэдгээр. кодоо А ангиллыг үүсгэх үед: A a = new A(); үнэн хэрэгтээ зөвхөн нэг А анги биш, харин хамааралтай ангиудын бүхэл бүтэн шатлал бий болсон бөгөөд үүний жишээг доорх зурагт үзүүлэв. Энэ шатлал нь "хатуу" юм: тусдаа ангиудын эх кодыг өөрчлөхгүйгээр та шаталсан ангиудын аль нэгийг нь сольж болохгүй. Иймээс ийм хэрэгжилтийн А анги нь өөрчлөгдөж буй орчинд дасан зохицох чадвар муутай байдаг. Энэ нь таны бичсэн кодоос өөр кодонд ашиглагдах боломжгүй байх магадлалтай.

Тодорхой хамаарлаас А ангиллыг салгахын тулд ашиглана уу хараат байдлын тарилга. Хамааралтай тарилга гэж юу вэ? Кодод шаардлагатай ангиллыг тодорхой үүсгэхийн оронд хамаарлыг байгуулагчаар дамжуулан А ангилалд шилжүүлдэг.

Нийтийн ангилал A ( хувийн эцсийн B b; нийтийн A(B b) ( this.b = b; ) public void someMethod() ( b.someMethodOfB(); ) )

Тэр. А анги одоо бүтээгчээр дамжуулан хараат байдлаа хүлээн авдаг. Одоо А анги үүсгэхийн тулд эхлээд түүний хамааралтай анги үүсгэх хэрэгтэй болно. IN энэ тохиолдолдэнэ бол Б:

B b = шинэ B(); A a = шинэ A(b); a.someMethod();

Хэрэв ижил процедурыг бүх ангиудад давтан хийвэл, i.e. D ангиллын жишээг B ангиллын бүтээгчид, түүний E ба F хамаарлыг D ангиллын бүтээгчид гэх мэтээр дамжуулснаар та бүх хамаарлыг урвуу дарааллаар үүсгэсэн кодыг авах болно.

G g = шинэ G(); H h = шинэ H(); F f = шинэ (g, h); E e = шинэ E(); D d = шинэ D(e,f); B b = шинэ B(d); A a = шинэ A(b); a.someMethod();

Үүнийг дараах байдлаар графикаар харуулж болно.

Хэрэв та 2 зургийг харьцуулж үзвэл - дээрх шууд хамаарал бүхий зураг, хараат байдлын тарилгатай хоёр дахь зураг - сумны чиглэл эсрэгээр өөрчлөгдсөнийг харж болно. Ийм учраас хэлц үгийг хараат байдлын “inversion” гэж нэрлэдэг. Өөрөөр хэлбэл хамаарлын урвуу байдал гэдэг нь анги өөрөө хамаарлыг үүсгэхгүй, харин үүсгэгч доторх үүсгэсэн хэлбэрээр хүлээн авдаг (эсвэл өөр хэлбэрээр).

Хамааралтай урвуу байдал яагаад сайн байдаг вэ? Dependency inversion-ийн тусламжтайгаар та анги дахь бүх хамаарлыг кодыг нь өөрчлөхгүйгээр сольж болно. Энэ нь таны А ангиллыг анх бичсэнээс өөр программд ашиглахаар уян хатан тохируулж болно гэсэн үг юм. Тэр. Уян хатан, модульчлагдсан, дахин ашиглах боломжтой кодыг бий болгоход хамаарлын урвуу зарчим (заримдаа хараат байдлыг шахах зарчим гэж нэрлэдэг) зарчим юм.

Хамааралтай тарилгын сул тал нь эхлээд харахад бас харагдаж байна - энэ загварыг ашиглан бүтээсэн ангиудын объектуудыг бүтээхэд маш их хөдөлмөр зарцуулдаг. Тиймээс хараат байдлын тарилгыг ихэвчлэн энэ ажлыг хөнгөвчлөх зорилготой зарим номын сантай хамт ашигладаг. Жишээлбэл, Google Guice номын сангуудын нэг. Cm.

2 хариулт

Сайн асуулт - урвуу үг нь зарим талаараа гайхмаар юм (Учир нь DIP-г хэрэглэсний дараа доод түвшний хамаарлын модуль нь одоо дуудагч модулиас илүү хамаарахгүй нь ойлгомжтой. өндөр түвшин: дуудагч эсвэл хамаарагч нь нэмэлт хийсвэрээр дамжуулан илүү чөлөөтэй холбогдсон байна).

Би яагаад "инверси" гэдэг үгийг ашигладаг юм бэ гэж асууж магадгүй. Шударга байхын тулд энэ нь илүү уламжлалт програм хангамж хөгжүүлэх аргууд, тухайлбал бүтэцлэгдсэн дүн шинжилгээ, дизайн нь өндөр түвшний модулиуд нь доод түвшний модулиудаас хамааралтай, хийсвэрлэл нь нарийн ширийн зүйлээс хамаардаг програм хангамжийн бүтцийг бий болгох хандлагатай байдагтай холбоотой юм. Үнэн хэрэгтээ эдгээр аргуудын нэг зорилго нь дээд түвшний модулиуд доод түвшний модулиуд руу хэрхэн дуудлага хийхийг тайлбарлах дэд программын шатлалыг тодорхойлох явдал юм... Иймээс сайн боловсруулсан объект хандалтат програмын хамаарлын бүтэц нь " ихэвчлэн уламжлалт процедурын аргын үр дүн болох хамаарлын бүтэцтэй харьцуулахад урвуу.

Боб авга ахын DIP-ийн нийтлэлийг уншихдаа анхаарах нэг зүйл бол C++ хэл нь интерфейсгүй (мөн бичих үед ч байхгүй) учраас C++ хэл дээр энэхүү хийсвэрлэлд хүрэх нь ихэвчлэн хийсвэр/цэвэр виртуал үндсэн ангиар хэрэгждэг. Java эсвэл C# хэл дээр холболтыг суллах хийсвэрлэл нь ихэвчлэн интерфэйсийг хамаарлаас салгаж, дээд түвшний модулийг интерфэйстэй холбох замаар салгах явдал юм.

ЗасварлахЗөвхөн тодруулахын тулд:

"Зарим газар би үүнийг хараат байдлын урвуу гэж нэрлэдэг"

Урвуу байдал:Аппликешнээс контейнер руу хамаарлын удирдлагыг эргүүлэх (жишээ нь, Spring).

Хамааралтай тарилга:

Үйлдвэрийн загвар бичихийн оронд объектыг шууд үйлчлүүлэгчийн ангилалд оруулбал ямар вэ. Тиймээс үйлчлүүлэгчийн ангиллыг интерфэйс рүү чиглүүлээрэй, бид үйлчлүүлэгчийн ангилалд тодорхой төрлийг оруулах боломжтой байх ёстой. Үүний тусламжтайгаар үйлчлүүлэгчийн анги нь шинэ түлхүүр үг ашиглах шаардлагагүй бөгөөд бетоны ангиас бүрэн тусдаа байдаг.

Хяналтын урвуу (IoC) талаар юу хэлэх вэ?

Уламжлалт програмчлалд бизнесийн логикийн урсгалыг бие биендээ статик байдлаар хуваарилсан объектуудаар тодорхойлдог. Удирдлагын урвуу байдлаар урсгал нь ассемблерийн жишээгээр үүсгэгдэж, хийсвэрлэлээр тодорхойлогдсон объектын харилцан үйлчлэлээр боломжтой болсон объектын графикаас хамаардаг. Үйлчилгээний байршил тогтоогчийг ашиглах нь хяналтын урвуу байдлыг бий болгодог гэж зарим хүмүүс маргадаг ч, холбох үйл явц нь хараат байдлыг шахах замаар хийгддэг.

Загварын удирдамж болгон хяналтыг эргүүлэх нь дараахь зорилгыг агуулна.

  • Тодорхой даалгаврын гүйцэтгэлийг түүний хэрэгжилтээс салгах явдал байдаг.
  • Модуль бүр юу хийхээр төлөвлөж байгаа дээрээ анхаарлаа төвлөрүүлж чадна.
  • Модулиуд нь бусад системүүд юу хийж байгаа талаар ямар ч таамаглал дэвшүүлдэггүй, харин тэдний гэрээнд тулгуурладаг.
  • Модулуудыг солих нь бусад модулиудад нөлөөлөхгүй.

Авахын тулд нэмэлт мэдээлэлхар.

14 хариулт

Үндсэндээ хэлэхдээ:

  • Хийсвэрлэл нь хэзээ ч нарийн ширийн зүйлээс хамаарах ёсгүй. Дэлгэрэнгүй мэдээлэл нь хийсвэрлэлээс хамаарах ёстой.

Энэ нь яагаад чухал вэ гэвэл, нэг үгээр хэлбэл: өөрчлөлт нь эрсдэлтэй бөгөөд хэрэгжилтээс илүү үзэл баримтлалаас хамааран та дуудлагын сайтууд дээр өөрчлөлт хийх хэрэгцээг багасгадаг.

DIP нь кодын өөр өөр хэсгүүдийн хоорондын холболтыг үр дүнтэйгээр багасгадаг. Мод бэлтгэгчийг хэрэгжүүлэх олон арга байдаг ч таны ашиглах арга нь цаг хугацааны явцад харьцангуй тогтвортой байх ёстой гэсэн санаа юм. Хэрэв та бүртгэл хөтлөх тухай ойлголтыг илэрхийлсэн интерфэйсийг задалж чадвал тухайн интерфейс нь хэрэгжүүлэхээс хамаагүй илүү тогтвортой байх ёстой бөгөөд дуудлага хийх сайтууд бүртгэл хөтлөх механизмыг хадгалах эсвэл өргөтгөх замаар таны хийж болох өөрчлөлтөд хамаагүй бага өртөмтгий байх ёстой.

Хэрэгжилт нь интерфэйсийн онцлогтой тул та өөрийн орчиндоо аль хэрэглүүрийг хамгийн сайн тохирохыг ажиллах үедээ сонгох боломжтой. Тохиолдолоос хамааран энэ нь бас сонирхолтой байж болно.

Agile Software Development, Principles, Patterns and Practices болон C# хэл дээрх Agile Principles, Patterns and Practices номууд нь Dependency Inversion Principle-ийн цаад зорилго, сэдлийг бүрэн ойлгох хамгийн сайн эх сурвалж юм. "Хараат байдлыг буцаах зарчим" нийтлэл нь бас сайн эх сурвалж боловч энэ нь төслийн хураангуй хувилбар бөгөөд өмнө дурдсан номуудад эцэст нь орсон тул багц өмчлөлийн тухай зарим чухал хэлэлцүүлгийг ардаа орхижээ. болон гол түлхүүр болох интерфэйсүүд Энэ зарчим нь "Дизайн загварууд" (Гамма, бусад) номноос олж авсан "хэрэгжүүлэхэд биш интерфэйсийн программ" гэсэн ерөнхий зөвлөмжөөс ялгаатай.

Товчхондоо, хамаарлын урвуу зарчмыг голчлон зорьдог өөрчлөхУламжлал ёсоор "дээд түвшний" бүрэлдэхүүн хэсгүүдээс "доод түвшний" бүрэлдэхүүн хэсгүүдийн хамаарлыг дамжуулж, ингэснээр "доод түвшний" бүрэлдэхүүн хэсгүүд нь интерфейсээс хамаардаг. эзэмшдэг"дээд түвшний" бүрэлдэхүүн хэсгүүдэд (Тэмдэглэл: "дээд түвшний" бүрэлдэхүүн хэсэг нь гаднах хамаарал/үйлчилгээг шаарддаг бүрэлдэхүүн хэсгийг хэлдэг ба давхаргат архитектур дахь концепцийн байрлалыг заах албагүй.) буурдагтүүн шиг ээлжонолын хувьд үнэ цэнэ багатай бүрэлдэхүүн хэсгүүдээс онолын хувьд илүү үнэ цэнэтэй бүрэлдэхүүн хэсгүүд.

Гадны хамаарал нь тухайн бүрэлдэхүүн хэсгийн хэрэглэгч хэрэгжилтийг хангах ёстой интерфейс хэлбэрээр илэрхийлэгддэг бүрэлдэхүүн хэсгүүдийг зохион бүтээх замаар үүнийг хийдэг. Өөрөөр хэлбэл, тодорхой интерфэйсүүд нь бүрэлдэхүүн хэсгийг хэрхэн ашиглахыг бус харин тухайн бүрэлдэхүүн хэсэг юу хэрэгтэй байгааг илэрхийлдэг (жишээлбэл, "IDoSomething" гэхээсээ илүү "INeedSomething").

Хамааралтай байдлыг хөрвүүлэх зарчимд заагаагүй зүйл бол интерфэйс ашиглан хамаарлыг хийсвэрлэх энгийн практик юм (жишээ нь: MyService -> ). Хэдийгээр энэ нь бүрэлдэхүүн хэсгийг хамаарлын тодорхой хэрэгжилтийн дэлгэрэнгүй мэдээллээс салгаж байгаа ч хэрэглэгч болон хамаарлын хоорондын хамаарлыг эргүүлдэггүй (жишээ нь, ⇐ Logger.

Хамааралтай байдлыг хөрвүүлэх зарчмын ач холбогдлыг нэг зорилгод багтааж болно - үйл ажиллагааныхаа зарим хэсгийг (бүртгэл, баталгаажуулалт гэх мэт) гадны хамаарлаас хамаардаг програм хангамжийн бүрэлдэхүүн хэсгүүдийг дахин ашиглах чадвар.

Дахин ашиглах энэхүү ерөнхий зорилгын хүрээнд бид дахин ашиглалтын хоёр дэд төрлийг ялгаж салгаж болно:

    Хамааралтай хэрэгжүүлэлт бүхий олон аппликешн дээр програм хангамжийн бүрэлдэхүүнийг ашиглах (жишээлбэл, та DI контейнер боловсруулсан бөгөөд бүртгэл хөтлөхийг хүсч байгаа боловч өөрийн контейнерийг тодорхой бүртгэл хөтлөгчтэй холбохыг хүсэхгүй байгаа тул таны контейнерыг ашигладаг хүн бүр бүртгэлийг ашиглах ёстой. таны сонгосон номын сан).

    Хөгжиж буй нөхцөл байдалд програм хангамжийн бүрэлдэхүүн хэсгүүдийг ашиглах (жишээлбэл, та програмын өөр өөр хувилбаруудад ижил хэвээр байх бизнесийн логик бүрэлдэхүүн хэсгүүдийг боловсруулсан бөгөөд хэрэгжүүлэх дэлгэрэнгүй мэдээлэл өөрчлөгддөг).

Дэд бүтцийн номын сан гэх мэт олон программууд дээр бүрэлдэхүүн хэсгүүдийг дахин ашиглах эхний тохиолдолд зорилго нь хэрэглэгчдийг өөрийн номын сангийн хамааралтай холбохгүйгээр үндсэн дэд бүтцээр хангах явдал юм. ижил хамаарал. Энэ нь таны номын сангийн хэрэглэгчид ижил дэд бүтцийн хэрэгцээнд (NLog, log4net гэх мэт) өөр номын санг ашиглахаар шийдсэн эсвэл шаардлагатай хувилбартай буцаах боломжгүй шаардлагатай номын сангийн дараагийн хувилбарыг ашиглахаар шийдсэн тохиолдолд асуудал үүсгэж болно. таны номын сангаар.

Бизнесийн логик бүрэлдэхүүн хэсгүүдийг дахин ашиглах хоёр дахь тохиолдолд (жишээ нь "Дээд түвшний бүрэлдэхүүн хэсэг") үндсэн талбар дахь програмын хэрэгжилтийг таны хэрэгжилтийн дэлгэрэнгүй мэдээллээс (жишээ нь: байнгын номын санг өөрчлөх/шинэчлэх, номын сангийн мессежийг солилцох) өөрчлөх) тусгаарлах явдал юм. . шифрлэлтийн стратеги гэх мэт). Хэрэглээний хэрэгжилтийн дэлгэрэнгүй мэдээллийг өөрчлөх нь програмын бизнесийн логикийг багтаасан бүрэлдэхүүн хэсгүүдийг эвдэж болохгүй.

Анхаарна уу. Зарим нь энэ хоёр дахь тохиолдлыг бодит дахин ашиглах гэж тайлбарлахыг эсэргүүцэж, нэг хөгжүүлж буй программд ашиглагдсан бизнесийн логик бүрэлдэхүүн хэсгүүд нь зөвхөн нэг хэрэглээг бүрдүүлдэг гэж үзэж болно. Энд байгаа санаа нь програмын хэрэгжилтийн нарийвчилсан өөрчлөлт бүр нь шинэ нөхцөл байдлыг илэрхийлдэг тул эцсийн зорилго нь тусгаарлах, зөөвөрлөх боломжтой гэж ялгаж болно.

Хоёрдахь тохиолдолд хараат байдлын урвуу зарчмыг дагаж мөрдөх нь тодорхой ашиг тустай байж болох ч Java, C# зэрэг орчин үеийн хэлнүүдэд хэрэглэх ач холбогдол нь ихээхэн буурч, магадгүй энэ нь хамааралгүй болтлоо буурсан гэдгийг тэмдэглэх нь зүйтэй. Өмнө дурьдсанчлан, DIP нь хэрэгжилтийн нарийн ширийн зүйлийг тусад нь багц болгон хуваах явдал юм. Хөгжиж буй програмын хувьд бизнесийн домайн нэр томъёонд тодорхойлсон интерфэйсийг ашиглах нь хэрэгжилтийн нарийвчилсан бүрэлдэхүүн хэсгүүдийн өөрчлөлтийн хэрэгцээ шаардлагаас шалтгаалан дээд түвшний бүрэлдэхүүн хэсгүүдийг өөрчлөх хэрэгцээ шаардлагаас хамгаалах болно, тэр ч байтугай хэрэгжилтийн дэлгэрэнгүй мэдээлэл нь эцсийн дүндээ нэг багцад байдаг ч гэсэн. . Зарчмын энэ хэсэг нь тухайн хэлийг кодчилох үед хамааралтай байсан (жишээ нь, C++) шинэ хэлнүүдэд хамааралгүй талуудыг тусгасан болно. Гэсэн хэдий ч Dependency Inversion зарчмын ач холбогдол нь юуны түрүүнд дахин ашиглах боломжтой програм хангамжийн бүрэлдэхүүн хэсэг/номын сангуудыг хөгжүүлэхтэй холбоотой юм.

Энэ зарчмын талаар илүү дэлгэрэнгүй авч үзэх болно хэрэглэхэд хялбаринтерфэйсүүд, хамаарлын тарилга, хуваах интерфэйсийн загварыг олж болно.

Програм хангамжийн хэрэглээг хөгжүүлэхдээ бид доод түвшний ангиуд - үндсэн болон үндсэн үйлдлүүдийг (дискний хандалт, сүлжээний протокол гэх мэт) хэрэгжүүлдэг ангиуд болон нарийн төвөгтэй логикийг (бизнесийн урсгал,... ) багтаасан өндөр түвшний ангиудыг авч үзэж болно. .

Сүүлийнх нь доод түвшний ангиудад тулгуурладаг. Ийм бүтцийг хэрэгжүүлэх байгалийн арга бол доод түвшний ангиудыг бичих бөгөөд бид өндөр түвшний нарийн төвөгтэй хичээлүүдийг бичих явдал юм. Өндөр түвшний ангиудыг бусдын өнцгөөс харж тодорхойлдог тул үүнийг хийх логик арга юм шиг санагддаг. Гэхдээ энэ нь мэдрэмжтэй дизайн биш юм. Хэрэв бид доод түвшний ангийг солих шаардлагатай бол яах вэ?

Хараат байдлын урвуу зарчимд дараахь зүйлийг заасан байдаг.

  • Өндөр түвшний модулиуд нь доод түвшний модулиудаас хамаарах ёсгүй. Аль аль нь хийсвэрлэлээс хамаарах ёстой.

Энэ зарчим нь дээд түвшний модулиудад байдаг ердийн санааг "хувиргах" зорилготой програм хангамждоод түвшний модулиудаас хамаарах ёстой. Энд дээд түвшний модулиуд нь доод түвшний модулиудаар хэрэгждэг хийсвэрлэлийг (жишээлбэл, интерфэйсийн аргуудыг шийдэх) эзэмшдэг. Тиймээс доод түвшний модулиуд нь дээд түвшний модулиудаас хамаардаг.

Хамааралтай урвуу байдлыг үр дүнтэй ашиглах нь таны хэрэглээний архитектурт уян хатан байдал, тогтвортой байдлыг хангадаг. Энэ нь таны програмыг илүү найдвартай, тогтвортой хөгжүүлэх боломжийг олгоно.

Уламжлалт давхаргат архитектур

Уламжлал ёсоор, давхаргат архитектурын хэрэглэгчийн интерфейс нь бизнесийн давхаргаас хамаардаг бөгөөд энэ нь эргээд өгөгдөлд нэвтрэх давхаргаас хамаардаг.

Та давхарга, багц эсвэл номын санг ойлгох ёстой. Код хэрхэн ажиллахыг харцгаая.

Бид өгөгдлийн хандалтын давхаргад зориулсан номын сан эсвэл багцтай байх болно.

// DataAccessLayer.dll нийтийн анги ProductDAO ( )

// DataAccessLayer ашиглан BusinessLogicLayer.dll; нийтийн ангилал ProductBO (хувийн бүтээгдэхүүнDAO бүтээгдэхүүнDAO; )

Хамааралтай урвуу байдал бүхий давхаргат архитектур

Хамааралтай урвуу байдал нь дараахь зүйлийг илэрхийлнэ.

Өндөр түвшний модулиуд нь доод түвшний модулиудаас хамаарах ёсгүй. Аль аль нь хийсвэрлэлээс хамаарах ёстой.

Хийсвэрлэл нь нарийн ширийн зүйлээс хамаарах ёсгүй. Дэлгэрэнгүй мэдээлэл нь хийсвэрлэлээс хамаарах ёстой.

Дээд түвшний болон доод түвшний модулиуд гэж юу вэ? Номын сан эсвэл багц зэрэг модулиудын талаар бодоход дээд түвшний модулиуд нь уламжлалт хамааралтай, доод түвшний модулиуд байх болно.

Өөрөөр хэлбэл, модулийн өндөр түвшин нь үйлдлийг дуудсан газар, доод түвшин нь үйлдлийг гүйцэтгэх газар байх болно.

Энэ зарчмаас үндэслэлтэй дүгнэлт хийж болно: зангилааны хооронд хамаарал байх ёсгүй, харин хийсвэрлэлээс хамааралтай байх ёстой. Гэхдээ бидний авч буй арга барилын дагуу бид хөрөнгө оруулалтын хамаарлыг буруу ашиглаж магадгүй, гэхдээ энэ нь хийсвэрлэл юм.

Бид кодоо дараах байдлаар тохируулна гэж төсөөлөөд үз дээ:

Бид хийсвэрлэлийг тодорхойлсон мэдээллийн хандалтын давхаргад зориулсан номын сан эсвэл багцтай байх болно.

// DataAccessLayer.dll нийтийн интерфейс IPProductDAO нийтийн анги ProductDAO: IPProductDAO( )

Өгөгдлийн хандалтын давхаргаас хамаарах бусад номын сан эсвэл багц түвшний бизнесийн логик.

// DataAccessLayer ашиглан BusinessLogicLayer.dll; нийтийн ангилал ProductBO (хувийн IPProductDAO productDAO; )

Хэдийгээр бид хийсвэрлэлээс хамааралтай ч бизнес болон өгөгдөлд нэвтрэх хоорондын хамаарал хэвээрээ байна.

Хараат байдлын урвуу байдалд хүрэхийн тулд тогтвортой интерфэйсийг доод түвшний модульд биш харин дээд түвшний логик эсвэл домэйн байрладаг модуль эсвэл багцад тодорхойлсон байх ёстой.

Эхлээд домэйн давхарга гэж юу болохыг тодорхойлж, түүний харилцааны хийсвэр байдлыг тууштай байдлаар тодорхойлно.

// Domain.dll нийтийн интерфейс IPProductRepository; DataAccessLayer ашиглах; нийтийн ангилал ProductBO (хувийн IPProductRepository productRepository; )

Тогтвортой байдлын түвшин нь домэйнээс хамааралтай болсны дараа хараат байдал тодорхойлогдсон тохиолдолд үүнийг өөрчлөх боломжтой болсон.

// Persistence.dll нийтийн анги ProductDAO: IPProductRepository( )

Зарчмыг гүнзгийрүүлэх

Үзэл баримтлалыг сайтар ойлгож, зорилго, ашиг тусыг гүнзгийрүүлэх нь чухал юм. Хэрэв бид механикийн чиглэлээр үлдэж, ердийн агуулахыг судлах юм бол бид хамаарлын зарчмыг хаана хэрэглэж болохыг тодорхойлох боломжгүй болно.

Гэхдээ бид яагаад хараат байдлыг өөрчилдөг вэ? Тодорхой жишээнүүдээс гадна гол зорилго нь юу вэ?

Энэ нь ихэвчлэн байдаг тогтворгүй зүйлээс хамааралгүй хамгийн тогтвортой зүйлсийг илүү олон удаа өөрчлөх боломжийг олгодог.

Домэйн логик эсвэл тууштай харилцах зорилготой үйлдлээс илүүтэй ижил мэдээллийн санд хандахын тулд өгөгдлийн сан эсвэл технологийг өөрчлөх нь илүү хялбар байдаг. Энэ нь хамааралтай байдлыг буцаахад хүргэдэг, учир нь энэ өөрчлөлт гарсан тохиолдолд тогтвортой байдлыг өөрчлөх нь илүү хялбар байдаг. Ингэснээр бид домэйныг өөрчлөх шаардлагагүй болно. Домэйн давхарга нь хамгийн тогтвортой нь учраас юунаас ч хамаарах ёсгүй.

Гэхдээ энэ хадгалалтын жишээнээс илүү зүйл бий. Энэ зарчмыг хэрэгжүүлэх олон хувилбарууд байдаг бөгөөд энэ зарчим дээр суурилсан архитектурууд байдаг.

архитектур

Хараат байдлын урвуу нь түүний тодорхойлолтын түлхүүр болдог архитектурууд байдаг. Бүх домэйнд энэ нь хамгийн чухал бөгөөд энэ нь домэйн болон бусад багц эсвэл номын сангуудын хоорондын харилцааны протоколыг тодорхойлох хийсвэрлэл юм.

Цэвэр архитектур

Миний хувьд хараат байдлын урвуу зарчмыг албан ёсны нийтлэлд тайлбарласан болно

C++ хэл дээрх асуудал нь толгой файлууд нь ихэвчлэн хувийн талбарууд болон аргуудын мэдэгдлүүдийг агуулсан байдаг. Хэрэв өндөр түвшний C++ модуль нь доод түвшний модулийн толгой файлыг агуулж байвал энэ нь бодит байдлаас хамаарна. хэрэгжилтЭнэ модулийн дэлгэрэнгүй мэдээлэл. Мөн энэ нь тийм ч сайн биш нь ойлгомжтой. Гэхдээ энэ нь өнөөдөр түгээмэл хэрэглэгддэг орчин үеийн хэл дээр асуудал биш юм.

Дээд түвшний модулиуд нь доод түвшний модулиудтай харьцуулахад дахин ашиглагдах чадвар багатай байдаг, учир нь эхнийх нь сүүлийнхтэй харьцуулахад илүү програм/контекст онцлогтой байдаг. Жишээлбэл, UI дэлгэцийг хэрэгжүүлдэг бүрэлдэхүүн хэсэг нь хамгийн дээд түвшний, бас маш (бүхэлдээ?) програмын онцлог юм. Ийм бүрэлдэхүүн хэсгийг өөр программд дахин ашиглахыг оролдох нь сөрөг үр дагавартай бөгөөд зөвхөн хэт хөгжихөд хүргэдэг.

Тиймээс, А бүрэлдэхүүн хэсэг нь В бүрэлдэхүүнээс хамаарах (А-аас хамаарахгүй) ижил түвшинд тусдаа хийсвэрлэл үүсгэх нь зөвхөн А бүрэлдэхүүн хэсэг нь өөр өөр программууд эсвэл контекстүүдэд дахин ашиглахад хэрэг болох тохиолдолд л хийгдэж болно. Хэрэв тийм биш бол DIP програм нь муу дизайн болно.

Хараат байдлын урвуу зарчмыг илэрхийлэх илүү тодорхой арга:

Бизнесийн нарийн төвөгтэй логикийг багтаасан модулиуд нь бизнесийн логикийг багтаасан бусад модулиудаас шууд хамаарах ёсгүй. Үүний оронд тэдгээр нь зөвхөн энгийн өгөгдлийн интерфейсээс хамаарах ёстой.

Өөрөөр хэлбэл, хүмүүс ихэвчлэн хийдэг шиг логик ангиа хэрэгжүүлэхийн оронд:

Ангийн хамаарал ( ... ) класс Логик ( private Dependency dep; int doSomething() ( // Энд dep ашиглан бизнесийн логик ) )

Та иймэрхүү зүйлийг хийх хэрэгтэй:

Class Dependency ( ... ) интерфейс Өгөгдөл ( ... ) анги DataFromDependency хэрэгжүүлдэг Data ( private Dependency dep; ... ) класс Логик ( int doSomething(Data data) ( // ямар нэг зүйлийг өгөгдөлтэй тооцоолох ) ) )

Өгөгдөл болон DataFromDependency нь Dependency-тэй биш харин Logic-тай нэг модульд амьдрах ёстой.

Яагаад энэ вэ?

Сайн хариултууд ба сайн жишээнүүдэнд бусад хүмүүс аль хэдийн өгсөн.

Хараат байдлын урвуу байдлын цэг нь програм хангамжийг дахин ашиглах боломжтой болгох явдал юм.

Гол санаа нь бие биенээсээ хамааралтай хоёр кодын оронд хийсвэр интерфейс дээр тулгуурладаг. Дараа нь та аль ч хэсгийг нөгөө хэсэггүйгээр дахин ашиглаж болно.

Энэ нь ихэвчлэн Java дахь Spring гэх мэт хяналтын савыг (IoC) эргүүлэх замаар хийгддэг. Энэ загварт объектуудын шинж чанарыг XML тохиргоогоор тохируулдаг бөгөөд объектууд гарч, тэдгээрийн хамаарлыг олохоос илүүтэй байдаг.

Энэ псевдокодыг төсөөлөөд үз дээ...

Нийтийн анги MyClass ( нийтийн үйлчилгээний myService = ServiceLocator.service; )

MyClass нь Service класс болон ServiceLocator ангиас шууд хамаардаг. Хэрэв та өөр программ дээр ашиглахыг хүсвэл энэ нь хоёуланд нь шаардлагатай. Одоо үүнийг төсөөлөөд үз дээ ...

Нийтийн анги MyClass ( нийтийн IService myService; )

MyClass одоо IService интерфэйс гэсэн нэг интерфейсийг ашиглаж байна. Бид IoC контейнерт энэ хувьсагчийн утгыг тогтоохыг зөвшөөрөх болно.

Хүнсний үйлдвэрлэгчээс бараагаа асуудаг зочид буудал байг. Зочид буудал нь хүнсний үүсгүүрт хоолны нэрийг (тахианы мах гэх мэт) өгдөг бөгөөд генератор нь хүссэн хоолоо зочид буудалд буцааж өгдөг. Гэтэл зочид буудал нь ямар төрлийн хоол авч, үйлчилж байгааг нь тоодоггүй. Ийнхүү Генератор зочид буудалд "Хоол" гэсэн шошготой хүнс нийлүүлдэг.

Энэ хэрэгжилт нь JAVA

Үйлдвэрийн аргатай FactoryClass. Хүнсний генератор

Нийтийн ангийн FoodGenerator ( Хүнсний хоол; нийтийн хоол getFood(Стрингийн нэр)( if(name.equals("fish"))( food = new Fish(); )else if(name.equals("chicken"))( food = new Chicken( )else food = null;

Ангийн тайлбар/Интерфэйс

Нийтийн хийсвэр анги Хоол ( //Чанарыг баталгаажуулахын тулд хүүхдийн ангийн аль нь ч энэ аргыг дарахгүй... public void quality())( String fresh = "Энэ бол шинэхэн" + getName(); String tasty = "Энэ бол амттай " + getName(); System.out.println(шинэхэн); System.out.println(амттай); ) нийтийн хийсвэр String getName(); )

Тахианы мах зарж байна (Бетон анги)

Public class Chicken extensions Food ( /*Бүх төрлийн хоол нь шинэхэн, амттай байх шаардлагатай тул * Тэд супер ангийн аргыг "property()"-аас давж гарахгүй*/ public String getName())( "Тахиа"-г буцаана; ) )

Загас хоол зардаг (Тодорхой ангилал)

Нийтийн ангийн Загас хоолыг сунгадаг ( /*Бүх хүнсний төрөл нь шинэхэн, амттай байх шаардлагатай тул * Тэд "property()" супер ангиллын аргыг давж гарахгүй*/ public String getName())( "Загас" буцаана; ) )

Эцэст нь

Зочид буудал

Public class Hotel ( public static void main(String args)( //Үйлдвэрийн анги ашиглах.... FoodGenerator foodGenerator = new FoodGenerator(); //Хүнсийг бий болгох үйлдвэрийн арга... Хоол хүнс = foodGenerator.getFood( "тахиа" хоол. чанар();

Таны харж байгаагаар зочид буудал нь тахианы мах эсвэл загас уу гэдгийг мэдэхгүй. Энэ нь зөвхөн хүнсний зүйл гэдгийг мэддэг, өөрөөр хэлбэл. Зочид буудал нь хоолны ангиллаас хамаарна.

Загас, тахиа анги нь Хүнсний ангиллыг хэрэгжүүлдэг бөгөөд зочид буудалтай шууд холбоогүй гэдгийг та анзаарсан байх. тэдгээр. тахиа, загасны мах нь хоолны ангиллаас хамаарна.

Энэ нь өндөр түвшний бүрэлдэхүүн хэсэг (зочид буудал) болон доод түвшний бүрэлдэхүүн хэсэг (загас, тахиа) нь хийсвэрлэлээс (хоол) хамаардаг гэсэн үг юм.

Үүнийг хамаарлын урвуу гэж нэрлэдэг.

Dependency Inversion Principle (DIP) гэж заасан байдаг

i) Өндөр түвшний модулиуд нь доод түвшний модулиудаас хамаарах ёсгүй. Аль аль нь хийсвэрлэлээс хамаарах ёстой.

ii) Хийсвэрлэл нь хэзээ ч нарийн ширийн зүйлээс хамаарах ёсгүй. Дэлгэрэнгүй мэдээлэл нь хийсвэрлэлээс хамаарах ёстой.

Нийтийн интерфэйс ICustomer ( string GetCustomerNameById(int id); ) public class Хэрэглэгч: ICustomer ( //ctor public Customer()() нийтийн стринг GetCustomerNameById(int id) ( "Дамми Хэрэглэгчийн нэр" буцаана; ) ) нийтийн анги CustomerFactory ( нийтийн статик ICustomer GetCustomerData() ( буцаах шинэ Customer(); ) ) public class CustomerBLL ( ICustomer _customer; public CustomerBLL() ( _customer = CustomerFactory.GetCustomerData(); ) олон нийтийн мөр GetCustomerNameById(int id)tomer(return.Gme); ) ) нийтийн ангийн програм ( статик хүчингүй Үндсэн() ( CustomerBLL customerBLL = new CustomerBLL(); int customerId = 25; string customerName = customerBLL.GetCustomerNameById(customerId); Console.WriteLine(customerName); Console.ReadKey();

Анхаарна уу. Анги нь тодорхой нарийн ширийн зүйлсээс (интерфэйсийн хэрэгжилт) бус интерфейс эсвэл хийсвэр анги зэрэг хийсвэрлэлээс хамаарах ёстой.

хуваалцах

Сүүлийн шинэчлэлт: 2016/03/11

Хараат байдлын урвуу байдлын зарчимХараат байдлын урвуу зарчмыг турших, өөрчлөх, шинэчлэхэд хялбар, сул холбогдсон объектуудыг бий болгоход ашигладаг. Энэ зарчмыг дараах байдлаар томъёолж болно.

Дээд түвшний модулиуд нь доод түвшний модулиудаас хамаарах ёсгүй. Аль аль нь хийсвэрлэлээс хамаарах ёстой.

Хийсвэрлэл нь нарийн ширийн зүйлээс хамаарах ёсгүй. Дэлгэрэнгүй мэдээлэл нь хийсвэрлэлээс хамаарах ёстой.

Зарчмыг ойлгохын тулд дараах жишээг анхаарч үзээрэй.

Ангийн ном ( public string Text ( get; set; ) public ConsolePrinter Printer ( get; set; ) public void Print() ( Printer.Print(Text); ) ) class ConsolePrinter ( public void Print(string text) ( Console.WriteLine (текст);

Номыг төлөөлдөг Book анги нь хэвлэхдээ ConsolePrinter классыг ашигладаг. Энэ тодорхойлолтоор Book анги нь ConsolePrinter ангиас хамаарна. Түүнээс гадна бид зөвхөн ConsolePrinter анги ашиглан ном хэвлэх ажлыг зөвхөн консол дээр хийж болно гэдгийг хатуу тодорхойлсон. Бусад сонголтууд, жишээлбэл, хэвлэгч рүү гаргах, файл руу гаргах эсвэл график интерфэйсийн зарим элементүүдийг ашиглах - энэ тохиолдолд энэ бүгдийг хассан болно. Ном хэвлэх хийсвэрлэл нь ConsolePrinter ангийн дэлгэрэнгүй мэдээлэлээс тусгаарлагдаагүй. Энэ бүхэн нь хараат байдлын урвуу зарчмыг зөрчсөн явдал юм.

Одоо ангиудаа хийсвэрлэлийг доод түвшний хэрэгжилтээс салгаж, хамаарлын урвуу зарчимд нийцүүлэхийг хичээцгээе.

Интерфэйс IPrinter ( void Print(string text); ) class Book ( public string Text ( get; set; ) public IPrinter Printer ( get; set; ) public Book(IPrinter printer) ( this.Printer = printer; ) public void Print( ) ( Printer.Print(Text); ) ) анги ConsolePrinter: IPrinter ( public void Print(string text) ( Console.WriteLine("Print to console"); ) ) class HtmlPrinter: IPrinter ( public void Print(string text) ( Console.WriteLine("html дээр хэвлэх");

Ном хэвлэх хийсвэрлэл нь одоо тодорхой хэрэгжилтээс тусгаарлагдсан. Үүний үр дүнд Book анги болон ConsolePrinter анги хоёулаа IPrinter хийсвэрлэлээс хамаардаг. Нэмж дурдахад, бид одоо IPrinter хийсвэрлэлийн нэмэлт доод түвшний хэрэгжилтийг үүсгэж, тэдгээрийг программд динамикаар ашиглах боломжтой.

Номын ном = шинэ ном(шинэ ConsolePrinter()); ном.Хэвлэх(); book.Printer = new HtmlPrinter(); ном.Хэвлэх();