Програм зохиох бол нарийн төвөгтэй ажил. Ямар ч програмын хувьд өөрийн хийх ажлаа гүйцэтгэхийн чацуу цаашдаа хөгжих, ажлын хүрээнд шинээр гарч ирэх илүү нарийн асуудлыг шийдвэрлэх боломжтой илүү уян хатан байдлаар зохиогдсон байх хэрэгтэй. Хэрвээ та програмын төслийн ахлагч, зохион бүтээгчээр ажиллаж байсан бол програмын ажиллагааг цаашдаа дэмжих, үйлчилгээ үзүүлэх, өргөжүүлэн хөгжүүлэхэд цаг хугацаа хожихын тулд кодыг нэг удаа хэрхэн яаж бичихийг тодорхойлох хамгийн төвөгтэй асуудал гэдгийг мэдэрсэн байх.
Нарийн төвөгтэй програмыг боловсруулахдаа та тухайн төсөл дээр ажиллаж байгаа цорын ганц хүн биш гэдгийг юуны өмнө бодолцох ёстой. Хоёрдугаарт цаашдаа програмд өөрчлөлт хийгдэн өргөжихийн зэрэгцээ техникийн үйлчилгээ шаардлагатай болно. Эцэст нь зөвлөхөд кодыг зөвхөн ганцхан удаа л бичихийг оролдох.
Хэрвээ та програм зохиож байсан бол боловсруулалтын үед олон асуудалтай тулгарсан байж таарна. Програмын ажиллагаанд байдаг ерөнхий асуудлуудын нэгдсэн шийдлийг гаргаад дараагийн ажилдаа түүнийгээ хэрэглэдэг. Ийм туршлага ямарч салбарын ажилд элбэг тохиолддог. Програмчлалын хувьд иймэрхүү шийдлийг програмчлалын хэв буюу design pattern гэж нэрлэдэг. Өөрөөр хэлбэл өмнө нь таарч байсан ерөнхий асуудлуудын нэгдсэн шийдэл юм.
Програмчлах явцад гардаг ерөнхий асуудлуудыг шийдэх олон төрлийн аргуудыг програм боловсруулагчид зохиосон байдаг бөгөөд эдгээр нь шинэ төслийг боловсруулах ажлыг хөнгөвчилж өгдөг. Иймд програм зохиогч болох гэж байгаа болон програм зохиогдог мэрэгжилтнүүд заавал судлан мэдсэн байх шаардлагатай гэж үзэн боловсруулалтын үндсэн хэвүүдийн талаар цуврал хичээлүүдийг сайтдаа тавьж байгаа юм. Яагаад энэ хэвүүдийг мэдэх, ашиглах хэрэгтэй юм бэ? гэсэн бодол орж ирж болох талтай. Сургуульд заалгаж байгаа програмчлалын хэлүүдийн хичээлүүдэд эдгээрийг оруулах нь цаг хугацаа, судлах материалууд, эзэмших зэрэгт асуудал үүсэх магадлалтай. Учир нь програмчлалын хэлийг дөнгөж заалгаж байгаа хүмүүс боловсруулалтын хэвийг ойлгоход хүнд, ашиглах тохиолдолууд голдуу практик буюу бодит төслүүд дээр голлон гарч ирдэгтэй холбоотой. Сургалтын жишээнд хэвүүдийг ашиглах нь ойлгомж муутай, давуу талуудыг олж харахад хангалтгүй. Зарим програм зохиогчид хэвүүд ашиглахгүйгээр програм зохиож болоод байдаг гэж үздэг. Хэрвээ та ганцаараа програм зохиодог бол ийм аргуудыг ашиглах эсэх нь таны хэрэг боловч та олон төсөл боловсруулж амжихгүй л болов уу. Өнөө үед ямарч ажлын хувьд богино хугацаанд, маш найдвартай ажиллагаатай гүйцэтгэл үндсэн шалгуур болсон тул та боловсруулалтын хэвийг мэдэхгүйгээр өөрийн өмнөх кодыг дахин ашиглах боломж багатай болохын дээр бусдын кодыг ойлгоход хүндрэлтэй. Олон боловсруулагчид оролцсон ажилд хэв ашиглахгүй бол нэгдсэн баг ажиллаж байна гэж үзэхэд хэцүү. Багийн гишүүн бүр өөрсдийн аргачлалаар кодоо бичээд явж байтал хэн нэг нь чөлөө авах эсхүл өвдөх, ажлаасаа гарсан тохиолдолд түүний ажлыг эхнээс нь хийхээс өөр арга бараг байхгүй болно. Хүн толгойдоо бодсон зүйлийг ойлгох гэснээс дахин бичсэн нь хамаагүй хурдан. Хэрвээ нэгдсэн хэвүүд ашиглаж байсан бол кодыг ойлгох, цаашид хөгжүүлэн сайжруулахад үнэхээр хөнгөн болно. Програм боловсруулах ажилд баримтлах журам, соёл гэж бий. Үүнийг бид бүр анхнаас нь чанд биелүүлж сурах хэрэгтэй. Энэ бол тусдаа сэдэв. Ингэхэд боловсруулалтын хэвийг зөвхөн програм зохиоход ашиглаад зогсохгүй програмын бүтэц, хэрэглэгчийн интерфейс, бусад олон асуудлыг шийдэхэд хэрэглэдэг гэдгийг дурдах нь зүйтэй.
Програмчлалын хэв /Pattern/ ашиглахын давуу талууд
Програм зохиох ажиллагаанд хэвүүд /паттерн/ ашиглах нь дараах давуу тулуудыг бий болгодог. Үүнд
- Програм зохиохдоо бид асуудлыг классууд, обьектууд болон тэдгээрийн хоорондын холбоос хэлбэрээр тодорхойлоод дараа нь түүнийг шийдвэрлэхдээ аль нэгэн хэвийг ашиглаж болно. Ингэснээр тодорхой асуудлыг шийдвэрлэх хэв байгаа учраас түүнийг ашигласнаар ямар нэгэн зүйлийг шинээр бодон олох шааардлагагүй.
- Аргачлалууд /хэвүүд/ програмчлалын хэлнээс хамааралгүй байдаг тул тэдгээрийг хэрэглэх зарчим C#, Java, PHP гэх мэтээр өөр бусад хэлүүдэд яг адилхан.
- Хэвүүдээр бодож сэтгэх нь програмыг багаар боловсруулах ажиллагааг хөнгөн болгодог. Багийн гишүүд загварчлалын хэвүүдийн /паттерн/ үндсэн зарчим, хэрэглэгээг мэддэг байснаар түүнийг ашиглах, багийн бусад гишүүдийн кодыг ойлгох, асуудлын шийдлийг ойлгоход дөхөмтэй.
Хэв ашиглахын төлөө паттернг хэрэглэж болохгүйг сануулах хэрэгтэй. Сайн програм гаргахын тулд хэвүүдийг ашиглахыг зөвлөдөг ч хэвүүд програмыг дандаа сайжруулж, хураангуйлаад байдаггүй. Тэдгээрийн буруу, зохимжгүй хэрэглээ нь програмын кодыг төвөгтэй болгох, түүний чанарыг муудуулж ч мэднэ. Иймээс загварчлалын хэвүүд асуудлыг шийдвэрлэх үр дүнтэй арга байснаар тэдгээрийн хэрэглээ баталгаажих ёстой.
Паттернуудын ангилал
Бүр 1977 оноос гарч ирсэн боловсруулалтын үндсэн хэвүүд тус бүрдээ тодорхой чиг үүрэг бүхий байгуулалтын (creational), бүтцийн (structural), төлөв байдлын (behavioral) гэсэн 3 ерөнхий төрөлд хуваагддаг. Үүнээс гадна хэрэглэгчийн интерфейсийн болон бүтцийн асуудлын өргөжүүлсэн загварууд ч бий. Эдгээр нь бүтцийн хэвийн ангилалд (architectural design patterns classification) ордог.
Байгуулалтын хэвүүд. /Creational Patterns/
Энэ төрлийн хэвүүд нь обьект, классуудыг үүсгэхтэй холбоотой асуудлуудыг шийдэхэд зориулагдсан.
Хэвийн нэр | Тодорхойлолт | Жишээ |
Abstract Factory | Тухайн классыг холбогдолтой, хамааралтай гэдгийг тодруулахгүйгээр обьект ба класуудыг үүсгэх үйлдвэрлэх /factory/ арга. | Factory.CreateProductA(); Factory.CreateProductB(); |
Factory Method | Классын ямар дэд классууд хувийг үүсгэхэд ашиглагдаж байгааг шийдэх боломжийг олгодог обьектыг үүсгэх интерфейсийг тодорхойлдог. | FactoryA.Create(); FactoryB.Create(); |
Builder | Обьект төрөл бүрийн үзүүлбэрийг /view/ дэмжиж болох байдлаар түүнийг үзүүлбэрээс салган үүсгэнэ. | Builder.BuildPartA(); Builder.BuildPartB(); Build.GetFinalProduct(); |
Prototype | Загварын жишээгээр үүсгэх шаардлагатай обьектын төрлийг заах ба шинэ обьектыг энэ загварыг хуулах замаар үүсгэдэг. | Product = Prototype.Clone(); |
Singleton | Классын хувьд хандах нэг ерөнхий оролтыг олгодог. Жишээ нь статик арга. | Singleton.DoSomething(); |
Бүтцийн хэвүүд. /Structural Patterns/
Обьект, классууд илүү том бүтцийг бий болгох, илүү нарийн шинж чанартай обьект, классуудйг үүсгэхтэй холбогдолтой асуудлуудыг шийдэхэд зориулагдсан хэвүүд.
Хэвийн нэр | Тодорхойлолт | Жишээ |
Adapter | Классын интерфейсийг хэрэглэгч хүлээн авах өөр интерфейст хувиргах. | Target obj = new Adapter(); obj.DoSomething(); |
Bridge | Хийсвэрлэлийг түүний гүйцэтгэлээс салган тэдгээрүүд хамааралгүйгээр өөрчлөгдөх боломжтой болгох. | var obj = new ConcreteA(); obj.DoSomething(); obj = new ConcreteB(); obj.DoSomething(); |
Composite | Нарийн шатлалын дүрслэлийг гаргахын тулд обьектуудыг мод бүтцэд нэмэх. | Composite.Add(objA); Composite.Add(objB); |
Decorator | Ашиглагдаж буй обьектыг динамикаар өргөжүүлэх. | obj.SetDecorator(decA); obj.DoDecoration(); obj.SetDecorator(decB); obj.DoDecoration(); |
Facade | Дэд системд бусад интерфейсүүдийг оруулахын тулд нэгдсэн интерфейсийг олгох. | Facade.MethodFromObjA(); Facade.MethodFromObjB(); |
Flyweight | Обьектуудын олонлогийг үүсгэх логикийг нэг обьектэд хайрцаглах /инкапсуляц/ замаар хэлбэржүүлэх. | A = FWFactory.GetFW("A"); B = FWFactory.GetFW("B"); |
Proxy | Өөр төрлийн обьектуудыг дүүргэгч. | var proxy = new Proxy(); proxy.RequestChannel(); |
Төлөв байдлын хэвүүд. /Behavioral Patterns/
Доорхи хүснэгтээр обьектууд эсхүл классуудын хоорондын харилцан үйлчлэл, төлөв байдалтай холбогдолтой асуудлуудыг шийдэхээр боловсруулагдсан хэвүүдийг үзүүллээ.
Хэвийн нэр | Тодорхойлолт | Жишээ |
Chain of Response | Илгээгч хүлээн авагчийг холбоог тойрон обьектод хүсэлтийг боловсруулах боломжийг олгох. | Employee.SetSupervisor(Manager); Manager.SetSupervisor(Director); Employee.Execute(); |
Command | Хүсэлтийг төрөл бүрийн команд бүхий обьект хэлбэрээр хайрцаглах. | Command.DoSomething(); Command.Redo(); Command.Undo(); |
Interpreter | Хэлний боломжийн тусламжаар үзүүлбэрийг тодорхойлох. Жишээ нь тогтмол илэрхийлэл эсхүл Flyweight хэвийн зарим гүйцэтгэлийг ашиглах | Vocabulary.Add(expressionA); Vocabulary.Add(expressionB); Vocabulary.Translate(); |
Mediator | Өөр хоорондоо харилцан ажиллаж болох обьектуудын багцыг өөртөө агуулсан обьектыг тодорхойлох. | Mediator.Add(ObjA); Mediator.Add(ObjB); ObjA.Send(“ObjB”, "Message"); |
Memento | Хайрцаглалтыг зөрчихгүйгээр дараа нь обьектыг байсан төлөвтэйгээр нь сэргээж болох байдлаар обьектын төлөвийг хадгалах. Жишээ нь LINQ to Entities эсхүл обьектын сериализацын үед ашигладаг. | ObjA.Name = “ObjA"; Memento.Save(ObjA); Memento.Restore(ObjA); |
Observer | "нэг - олон" хэлбэрийн обьектуудын хоорондын харилцааг нэг обьект өөрчлөгдөхөд түүний бүх охин /дагалдах/ обьектууд энэ тухай мэдээллийг автоматаар аван шинэчлэгдэх байдлаар тодорхойлох. | Observer.Attach(ObjA); Observer.Attach(ObjB); Observer.ChangeSomething(); Observer.Notify(); |
State | Обьектын дотоод төлөвд өөрчлөлт ороход тэрээр төлөв байдлаа өөрчлөх боломжийг олгох. | Context.Add(ObjA); ObjA.ChangeState(“A"); ObjA.ChangeState(“B”); |
Strategy | Обьектуудын багцуудын ажиллагаанд хэд хэдэн алгоритмыг тодорхойлно. | List.Add(ObjA); List.Add(ObjB); List.SortStrategy(Ascending); List.SortStrategy(Descending); |
Template Method | Аргын доторхи алгоритмын бүтцийг энэхүү аргад дамжуулсан классын хувийн төрлөөс хамааруулан тодорхойлох. | Template A = new Student(); Template B = new Teacher(); A.Write(); B.Write(); |
Visitor | Обьектуудын структуртай ажиллах аргыг нэмэх. | List.Add(Student(“A”)); List.Add(Student(“B”)); List.Visit(new VoteVisitor()); |
Энд зөвхөн боловсруулалтын үндсэн хэвүүдийг үзүүлсэн байгаа. Боловсруулалтын хэвүүд их олон тооны байдаг учраас та эдгээрийг цээжлэх эсхүл бүгдийг бүрэн хэмжээнд ойлгох гэсний хэрэггүй. Үүний оронд хэвүүдийг тодорхой жишээнд хэрхэн хэрэглэдэгийг ойлгон авах нь илүү.
Хэвүүдийг хэрхэн сонгох
Ямар нэгэн асуудлыг шийдвэрлэхийн тулд юуны өмнө түүнд хэрэглэгдэж буй бүх зүйлсүүд болон тэдгээрийн хоорондын холбоог тогтоогоод тодорхой нөхцөл байдлаас тэдгээрийн хийсвэрлэлтийг хийх хэрэгтэй. Дараа нь асуудлын шийдлийн хийсвэр хэлбэр тодорхой хэвд агуулагдаж буйг харна. Жишээ нь шийдэх асуудлын утга шинэ обьект үүсгэх байлаа гэвэл байгуулалтын хэвүүдийг авч үзэж болох юм. Гэхдээ асуудлыг шийдэхэд хэрэгтэй гэсэн ганцхан хэвийг шууд сонголгүй ижил төрлийн асуудлыг шийдэх тухайн бүлгийн хэдэн хэвийг авч үзэх нь илүү.
Ингэхдээ хэвийн утга, зориулалт, түүний зохион байгуулалтын хийсвэрлэлт, тодорхой хэрэгжүүлэлтийг яг зөв ойлгосон байх нь чухал. Нэг хэв янз бүрийн хэрэгжүүлэлтүүдтэй байж болох бөгөөд тэдгээртэй олон удаа ажиллах тусмаа та тухайн хэвийн утга учрыг илүү ойлгоно. Хэрвээ хэвийг сайн ойлгоогүй бол танд асуудлыг шийдвэрлэхэд хэрэг болохоор санагдаж байсан ч түүнийг хэрэглэх хэрэггүй.
Эцсийн дүнд програмын кодыг боломжийн хэмжээнд энгийн, ойлгомжтой байлгах үүднээс KISS (Keep It Simple, Stupid - Ойлгомжгүй болгосноос энгийн байдлыг хадгал) зарчмыг баримтлах хэрэгтэй. Програмчлалын хэвүүдийг ашиглах утга учир нь кодыг хүнд болгоход бус харин түүнийг энгийн ойлгомжтой болгох шүү дээ.
Зөвлөмж: Програмчлалын хэвүүдийг дан ганц кодлогчид гэлтгүй системийн болон өгөгдлийн сангийн аналитик, тестлэгч зэрэг бүтээгдхүүн боловсруулалтын багийн гишүүд ямар нэгэн хэмжээнд мэддэг байх хэрэгтэй. Эхэн үедээ хэвүүд /паттерн/ ойлгомжгүй болоод төвөгтэй мэт санагдаж магадгүй. Сайн мэрэгжилтэн болно гэж бодож байвал үүнийг судлан ойлгож ашиглаж сурахаас аргагүй.