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


АНХААРУУЛГА: Энэ нийтлэлийн зохиогч нь "авга ах" Боб Мартин шиг нэр хүндтэй нөхрийг доромжлох, эсвэл ямар нэгэн байдлаар доромжлох зорилгогүй. Энэ нь хамаарлын урвуу зарчмын талаар илүү анхааралтай бодож, түүнийг тайлбарлах жишээнүүдэд дүн шинжилгээ хийх явдал юм.

Нийтлэлийн туршид би дээр дурдсан эх сурвалжаас шаардлагатай бүх ишлэл, жишээг өгөх болно. Гэхдээ "спойлер"-ээс зайлсхийхийн тулд таны бодол бодитой хэвээр байхын тулд би 10-15 минут зарцуулж, энэ зарчмын анхны тайлбарыг нийтлэл эсвэл номноос уншихыг зөвлөж байна.

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

A. Дээд түвшний модулиуд нь доод түвшний модулиудаас хамаарах ёсгүй. Аль аль нь хийсвэрлэлээс хамаарах ёстой.
B. Хийсвэрлэл нь нарийн ширийн зүйлээс хамаарах ёсгүй. Нарийвчилсан мэдээлэл нь хийсвэрлэлээс хамаарах ёстой.
Эхний цэгээс эхэлье.

Давхарга

Сонгино нь давхаргатай, бялуу нь давхаргатай, каннибалууд давхаргатай, програм хангамжийн системүүд нь давхаргатай байдаг! - Шрек (в)
Аливаа нарийн төвөгтэй систем нь шаталсан байдаг: давхарга бүр нь доод түвшний батлагдсан, сайн ажилладаг давхарга дээр суурилдаг. Энэ нь үндсэн давхаргууд хэрхэн хэрэгжиж байгаа талаар бодохгүйгээр нэгэн зэрэг хязгаарлагдмал багц үзэл баримтлалд анхаарлаа төвлөрүүлэх боломжийг олгодог.
Үүний үр дүнд бид дараах диаграмтай төстэй зүйлийг олж авна.

Зураг 1 - "Гэнэн" давхаргын схем

Боб Мартины үүднээс авч үзвэл системийг давхаргад хуваах ийм схем юм гэнэн. Энэхүү дизайны сул тал нь "мэдрэмжтэй шинж чанар: давхарга Бодлогохүрэх зам дахь бүх давхаргын өөрчлөлтөөс хамаарна Хэрэгсэл. Энэ хамаарал нь шилжилтийн шинж чанартай байдаг.» .

Хмм... Маш ер бусын мэдэгдэл. Хэрэв бид .NET платформын талаар ярих юм бол одоогийн модуль нь нийтийн интерфэйс дэх доод түвшний модулиудыг "илчлэх" тохиолдолд л хамааралтай байх болно. Өөрөөр хэлбэл, хэрэв байгаа бол МеханизмДавхаргажишээг аргумент болгон авдаг нийтийн анги байдаг StringUtil(аас ХэрэгсэлДавхарга), дараа нь түвшний бүх үйлчлүүлэгчид МеханизмДавхаргадонтох ХэрэгсэлДавхарга. Үгүй бол өөрчлөлтийн шилжилт байхгүй болно: доод түвшний бүх өөрчлөлтүүд нь одоогийн түвшинд хязгаарлагдах ба түүнээс дээш тархдаггүй.

Боб Мартины санааг ойлгохын тулд та хамаарлын урвуу зарчмыг анх 1996 онд тайлбарлаж, C++ хэлийг жишээ болгон ашиглаж байсныг санах хэрэгтэй. Анхны нийтлэлд зохиолч өөрөө ингэж бичжээ Шилжилтийн асуудал нь ангийн интерфейсийг хэрэгжилтээс тодорхой салгахгүйгээр зөвхөн хэл дээр л байдаг. C++ хэл дээр шилжилтийн хамаарлын асуудал үнэхээр хамааралтай: хэрэв файл бол PolicyLayer. h"include" удирдамжаар орно Механизмын давхарга. h, энэ нь эргээд орно UtilityLayer. h, дараа нь толгой файлын өөрчлөлтийн хувьд UtilityLayer. h(энэ файлд заасан ангиудын "хаалттай" хэсэгт ч гэсэн) бид бүх үйлчлүүлэгчдийг дахин эмхэтгэж, дахин байршуулах шаардлагатай болно. Гэсэн хэдий ч C++ хэл дээр энэ асуудлыг Herb Sutter-ийн санал болгосон PIml хэлцийг ашиглан шийдэж байгаа бөгөөд одоо тийм ч хамааралгүй юм.

Боб Мартины үүднээс энэ асуудлыг шийдэх арга нь:

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



Зураг 2 – Урвуутай давхаргууд

Зарим талаараа энэ хуваагдал нь утга учиртай юм. Жишээлбэл, ажиглагчийн хэв маягийг ашиглах үед энэ нь гадаад ертөнцтэй харилцах интерфейсийг тодорхойлдог ажиглагдсан объект (ажиглагдах боломжтой) тул гадны ямар ч өөрчлөлт түүнд нөлөөлөхгүй.

Гэхдээ нөгөө талаас, ихэвчлэн угсралт (эсвэл UML хэлээр багц) хэлбэрээр илэрхийлэгддэг давхаргуудын тухай ярих юм бол санал болгож буй хандлагыг амьдрах чадвартай гэж нэрлэх нь бараг боломжгүй юм. Тодорхойлолтоор доод түвшний туслах ангиудыг дээд түвшний хэдэн арван өөр модульд ашигладаг. Хэрэглээний давхарга-д төдийгүй ашиглах болно Механизмын давхарга, гэхдээ бас дотор Өгөгдөл хандалтын давхарга, Тээврийн давхарга, Бусад давхарга. Энэ нь бүх дээд түвшний модулиудад тодорхойлсон интерфейсүүдийг хэрэгжүүлэх ёстой юу?

Мэдээжийн хэрэг, бид .NET эсвэл Java зэрэг олон платформ дээр байдаггүй асуудлыг шийдэж байгаа тул энэ шийдэл нь тийм ч тохиромжтой биш юм.

Хийсвэрлэлийн тухай ойлголт

Олон нэр томьёо бидний тархинд маш ихээр шингэж, бид тэдэнд анхаарал хандуулахаа больдог. Ихэнх "объект хандалтат" програмистуудын хувьд энэ нь бид "хийсвэрлэл", "полиморфизм", "инкапсуляция" гэх мэт хэтрүүлэн ашигласан олон нэр томъёоны талаар бодохоо больсон гэсэн үг юм. Бүх зүйл аль хэдийн тодорхой болсон тул яагаад тэдний тухай бодох вэ? ;)

Гэсэн хэдий ч, хараат байдлын урвуу зарчим болон тодорхойлолтын хоёр дахь хэсгийн утгыг зөв ойлгохын тулд бид эдгээр үндсэн ойлголтуудын аль нэг рүү буцах хэрэгтэй. Гради Бучагийн номноос "хийсвэрлэл" гэсэн нэр томъёоны тодорхойлолтыг харцгаая.

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

Өөрөөр хэлбэл хийсвэрлэл нь програмчлалын хэлээр тухайн объектын нийтийн (болон хамгаалагдсан) интерфейсээр тодорхойлогддог объектын харагдах байдлыг тодорхойлдог. Бид ихэнхдээ интерфэйс эсвэл хийсвэр анги ашиглан хийсвэрлэлийг загварчилдаг ч OOP үүднээс авч үзвэл энэ нь шаардлагагүй юм.

Тодорхойлолт руу буцаж орцгооё: Хийсвэрлэл нь нарийн ширийн зүйлээс хамаарах ёсгүй. Нарийвчилсан мэдээлэл нь хийсвэрлэлээс хамаарах ёстой.

Энэ нь юу болохыг санасны дараа одоо ямар жишээ санаанд орж ирдэг вэ? хийсвэрлэл? Хэзээ хийсвэрлэл нь нарийн ширийн зүйлээс хамааралтай болж эхэлдэг вэ? Энэ зарчмыг зөрчсөн жишээ бол хийсвэр анги юм GZipStream, авдаг MemoryStream, хийсвэр анги биш Дамжуулах:

GZipStream хийсвэр анги ( // GZipStream хийсвэрлэл нь GZipStream (MemoryStream memoryStream) () ) хамгаалагдсан бетон урсгалыг хүлээн авдаг.

Энэ зарчмыг зөрчиж буй өөр нэг жишээ бол бүтээгчээс авсан өгөгдлийн хандалтын давхаргаас хийсвэр агуулах анги юм. PostgreSqlConnectionэсвэл SQL Server-д зориулсан холболтын стринг нь ийм хийсвэрлэлийн аливаа хэрэгжилтийг тодорхой хэрэгжилттэй холбодог. Гэхдээ энэ нь Боб Мартин гэсэн үг үү? Нийтлэл эсвэл номонд дурдсан жишээнүүдээс харахад Боб Мартин "хийсвэрлэл" гэсэн ойлголтоос огт өөр зүйлийг ойлгодог.

зарчимДҮРЭХМартины хэлснээр

Түүний тодорхойлолтыг тайлбарлахын тулд Боб Мартин дараах тайлбарыг өгдөг.

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

  • Тодорхой ангиудын лавлагааг хадгалах хувьсагч байх ёсгүй.
  • Бетоны ангиас үүсэлтэй анги байх ёсгүй.
  • Суурь ангиудын аль нэгэнд хэрэгжсэн аргыг дарах аргууд байх ёсгүй.

DIP зарчмыг ерөнхийд нь зөрчиж, эхний "тодруулах" цэг, тухайлбал дараахь жишээг үзүүлэв.

Нийтийн ангиллын товчлуур ( хувийн чийдэн; нийтийн хүчингүй санал асуулга() (хэрэв (/* зарим нөхцөл */) чийдэн.TurnOn(); ) )

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

Код нь нэг сонирхолтой онцлогтой. Ховор тохиолдлыг эс тооцвол код нь өөрөө зөв эсвэл буруу байж болохгүй; Энэ нь алдаа эсвэл онцлог эсэх нь юу хүлээж байгаагаас хамаарна. Албан ёсны тодорхойлолт байхгүй байсан ч (энэ нь норм юм) код нь шаардлагатай эсвэл хийхээр төлөвлөснөөс өөр зүйл хийсэн тохиолдолд л буруу болно. Тодорхойлолт (зорилго) нь урьдчилсан нөхцөл, дараах нөхцөл, инвариант хэлбэрээр шууд кодоор илэрхийлэгддэг гэрээний програмчлалын үндэс нь энэ зарчим юм.

Анги руу харж байна ТовчлуурЗагвар нь гажигтай эсэхийг би хэлж чадахгүй. Ангийн нэр нь түүний хэрэгжилттэй тохирохгүй байна гэж би тодорхой хэлж чадна. Ангийн нэрийг өөрчлөх шаардлагатай Дэнлүүний товчлуурэсвэл ангиас хасна Товчлуурталбар Дэнлүү.

Боб Мартин "Өндөр түвшний хэрэглээний стратеги нь доод түвшний хэрэгжилтээс тусгаарлагдаагүй тул энэ загвар нь алдаатай гэж үзэж байна. Хийсвэрлэл нь нарийн ширийн зүйлээс тусгаарлагддаггүй. Ийм тусгаарлалт байхгүй тохиолдолд дээд түвшний стратеги нь доод түвшний модулиудаас автоматаар хамаардаг бөгөөд хийсвэрлэл нь нарийн ширийн зүйлээс автоматаар хамаардаг."

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

Мартины шийдэл нь:



Зураг 3 – “Хараат байдлыг эргүүлэх”

Энэ шийдэл нь илүү дээр үү? Ингээд харцгаая…

"Мартины хэлснээр" хамаарлыг эргүүлэхийн гол давуу тал нь өмчлөлийн урвуу байдал юм. Анхны загварт, анги солих үед Дэнлүүанги солигдох ёстой Товчлуур. Одоо анги Товчлууринтерфэйсийг "эзэмшинэ" ButtonServer, гэхдээ энэ нь "доод түвшний" өөрчлөлтийн улмаас өөрчлөгдөх боломжгүй, тухайлбал Дэнлүү. Энэ нь яг эсрэгээрээ: ангийн өөрчлөлт ButtonServerЭнэ нь зөвхөн Button ангиллын өөрчлөлтийн нөлөөн дор боломжтой бөгөөд энэ нь ангийн бүх удамд өөрчлөлт оруулах болно. ButonServer!

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

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

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

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

Одоо сул холбогч нь үйлдэл дээр ямар байдгийг тодорхой харуулах жишээг харцгаая.

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

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

  • Яагаад бялуу гэж? Та бялуу эсвэл бялуу захиалж болно
  • Яагаад төрсөн өдрөөрөө тусгайлан зориулсан бэ? Хурим эсвэл төгсөлтийн баяр байсан бол яах вэ?
  • Яагаад "тансаг", "Anthill" эсвэл "Прага"-д илүү дуртай бол яах вэ?
  • Яагаад хотын төвд эсвэл өөр газар байдаг нарийн боовны дэлгүүр биш, яг энэ нарийн боовны үйлдвэр гэж?

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

Одоо төрлүүдийг өөрсдөө барьж эхэлцгээе.

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

Интерфэйс IPastry (мөрийн нэр (авах; тохируулах; ))

Мөн энд тодорхой хэрэгжилт байна, бидний хувьд - төрсөн өдрийн бялуу. Таны харж байгаагаар төрсөн өдрийн бялуунд лаа ордог уламжлалтай)))

Ангийн төрсөн өдрийн бялуу: IPastry ( public int NumberOfCandles ( get; set; ) public string Name ( get; set; ) public override string ToString() ( return String.Format("(0) with (1) candle nices", Name, NumberOfCandles ); ))

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

Дараагийн асуулт бол нарийн боовны бүтээгдэхүүн бие биенээсээ хэрхэн ялгаатай вэ (мэдээж нэрнээс бусад). Мэдээжийн хэрэг, жороор!

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

Interface IIIngredient ( string IngredientName ( авах; багц; ) давхар Тоо хэмжээ ( авах; багц; ) мөр Нэгж ( авах; багц; ) )

Манай бялууны орцууд: гурил, цөцгийн тос, элсэн чихэр, цөцгий:

Анги гурил:IIОрц ( нийтийн мөр Орц нэр ( авах; багц; ) нийтийн давхар Тоо хэмжээ ( авах; багц; ) нийтийн мөр Нэгж ( авах; багц; ) нийтийн мөр Чанар ( авах; багц; ) ) анги Цөцгийн тос: IIБүрц ( нийтийн мөр Орцын нэр ( авах; багц; ) нийтийн давхар Тоо хэмжээ ( авах; багц; ) нийтийн мөр Нэгж ( авах; багц; ) ) ангилал Сахар: IIБүрц ( нийтийн мөр Орц нэр ( авах; багц; ) нийтийн давхар Тоо хэмжээ ( авах; багц; ) нийтийн мөр Нэгж ( авах; багц; ) нийтийн мөр Төрөл ( авах; багц; ) ) анги Цөцгий: IIБүрц ( нийтийн мөр IngredientName ( авах; багц; ) нийтийн давхар Тоо хэмжээ ( авах; багц; ) нийтийн мөр Нэгж ( авах; багц; ) нийтийн давхар өөх (авах; багц; ))

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

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

Интерфэйс IRecipe ( PastryType төрөл ( авах; тохируулах; ) мөрийн нэр ( авах; тохируулах;) IList Найрлага ( get;set;) string Description ( get;set;) )

Тодруулбал, төрсөн өдрийн бялууны жорыг төлөөлж буй анги дараах байдалтай байна.

Ангийн төрсөн өдрийн бялуу жор: IRRecipe ( нийтийн Төрөл PastryType ( авах; багц; ) нийтийн мөр Нэр ( авах; тохируулах;) нийтийн IList Найрлага ( авах; багц; ) нийтийн мөр Тайлбар ( авах; багц; ) нийтийн BirthdayCakeReipe() ( Найрлага = шинэ жагсаалт (); } }

Одоо гудамжны булан дахь гайхамшигтай нарийн боовны цех рүүгээ явцгаая.

Мэдээжийн хэрэг, бид бусад олон нарийн боовны газруудад хэрэглэж болох тул бид үүний үндсэн интерфейсийг тодорхойлох болно. Талх нарийн боовны хувьд хамгийн чухал зүйл юу вэ? Бүтээгдэхүүнийг жигнэх чадвартай.

Интерфейс IBakery (IPastry Bake(IRecipe жор); )

Манай нарийн боовны үйлдвэрийг төлөөлж буй анги энд байна:

NiceBakeryOnTheCornerOFMyStreet анги ( толь бичиг цэс = шинэ толь бичиг (); public void AddToMenu(IRecipe жор) ( хэрэв (!цэс.ContainsKey(жор.Нэр)) ( цэс.Нэмэх(жор.Нэр, жор); ) өөр ( Console.WriteLine("Энэ нь аль хэдийн цэсэнд байгаа"); ) ) нийтийн IRecipe FindInMenu(string name) ( if (menu.ContainsKey(name)) ( буцах цэс; ) Console.WriteLine("Уучлаарай...одоогоор бидэнд " + нэр байхгүй); буцах null; ) public IPastry Bake (IRRecipe жор) ( if (жор != null) ( IPastry pastry = Activator.CreateInstance(recipe.PastryType) IPastry; if (pastry != null) ( pastry.Name = жор.Нэр; боовыг IPastry гэж буцаана; ) ) null буцаана;))

Үлдсэн зүйл бол кодыг шалгах явдал юм:

Ангийн хөтөлбөр ( static void Main() ( //талбайны ангийн инктийг бий болгох var bakery = new NiceBakeryOnTheCornerOFMyStreet(); //жорын орцыг бэлтгэх var гурил = шинэ Flour() ( IngredientName = "Гурил", Тоо хэмжээ = 1.5 , Нэгж = "кг" ); var цөцгийн тос = шинэ цөцгийн тос() ( Орц нэр = "Цөцгийн тос", Тоо хэмжээ = 0.5, Нэгж = "кг" ); var элсэн чихэр = шинэ сахар() ( Найрлага = "Сахар", Тоо хэмжээ = 0.7 , Нэгж = "кг" ); var creme = шинэ Creme() ( Орц нэр = "Цөцгий", Тоо хэмжээ = 1.0, Нэгж = "литр" ); //мөн энэ нь жор өөрөө var weddingCakeRecipe = new BirthdayCakeRecipe() ( PastryType = typeof(Төрсөн өдрийн бялуу), Нэр = "Төрсөн өдрийн бялуу тансаг", Тодорхойлолт = "төрсөн өдрийн сайхан бялууг хэрхэн хийх тухай тайлбар" ); weddingCakeRecipe.Ingredients.Add(гурил); WeddingCakeRecipe.Ingredients.Add(цөцгийн); WeddingCakeRecipe.Ingredients .Нэмэх(элсэн чихэр); хуримын бялууны жор.Орц.Нэмэх(цөцгий); //бялууны жорыг талх нарийн боовны нарийн боовны цэсэнд нэмэх.AddToMenu(weddingCakeRecipe); //одоо захиалгаа өгцгөөе!! Төрсөн өдрийн бялуу = bakery.Bake(bakery.FindInMenu("Төрсөн өдрийн бялуу тансаг")) Төрсөн өдрийн бялуу болгон; //бага лаа нэмж байна;) бялуу.NumberOfCandles = 10; //бид энд ирлээ. !!! Console.WriteLine(бялуу); ) )

Одоо кодыг бүхэлд нь дахин харж, үнэлье. Код нь маш энгийн, төрөл, тэдгээрийн хийсвэрлэл, өгөгдөл, функцийг тодорхой зааж өгсөн, код нь өргөтгөх, дахин ашиглах боломжийг олгодог. Сегмент бүрийг үндсэн төрөлд тохирсон өөр зүйлээр өвдөлтгүй сольж болох бөгөөд энэ нь бусад кодыг сүйрүүлэхгүй.

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

Муу үр дүн биш. Бид хичээлүүдийг бие биентэйгээ хамгийн бага холбоотой болгохыг хичээсэнд баярлалаа.

Одоо хараат байдлын урвуу зарчмыг зөрчсөний үр дагаврын талаар бодоцгооё.

  1. хатуу байдал (системд ямар нэгэн өөрчлөлт хийх нь маш хэцүү байх болно, учир нь өөрчлөлт бүр нь түүний олон хэсэгт нөлөөлсөн).
  2. эмзэг байдал (системийн нэг хэсэгт ямар нэгэн өөрчлөлт хийх үед түүний бусад хэсгүүд эмзэг болдог, заримдаа энэ нь эхлээд харахад тийм ч тодорхой биш байдаг).
  3. хөдөлгөөнгүй байдал (модулиуд нь хоорондоо нягт холбоотой байдаг тул та бусад системд кодыг дахин ашиглахаа мартаж болно).

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

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; ... ) class Logic ( 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()"*/ нийтийн 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); ) ) нийтийн анги Програм ( static void Main() ( 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(); ном.Хэвлэх();