0% found this document useful (1 vote)
296 views46 pages

OOP in Delphi Arabic

This document discusses object-oriented programming in Delphi. It provides an overview of classes and objects in Delphi, defining classes, method overloading, encapsulation using properties, inheritance, polymorphism, and interfaces. Delphi is an object-oriented extension of the Pascal programming language, and Borland later marketed it as an independent language rather than just a development environment.

Uploaded by

Maya Daya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (1 vote)
296 views46 pages

OOP in Delphi Arabic

This document discusses object-oriented programming in Delphi. It provides an overview of classes and objects in Delphi, defining classes, method overloading, encapsulation using properties, inheritance, polymorphism, and interfaces. Delphi is an object-oriented extension of the Pascal programming language, and Borland later marketed it as an independent language rather than just a development environment.

Uploaded by

Maya Daya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 46

‫ﺗﻢ ﺗﺤﻤﻴﻞ اﻟﻤﻠﻒ ﻣﻦ ﻣﻮﻗﻊ‬

‫اﻟﺒﻮﺻﻠﺔ اﻟﺘﻘﻨﻴﺔ‬
‫‪www.boosla.com‬‬
‫ﺍﻟﻔﺼﻞ ﺍﻷﻭﻝ‬

‫‪OOP in Delphi‬‬
‫ﺍﻟﱪﳎﺔ ﻏﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟ‪‬ـﻪ ﰲ ﺩﻟﻔﻲ‬

‫‪www.orwah.net‬‬ ‫ﻋﺮوة ﻋﻠﻲ ﻋﯿﺴﻰ ‪ .‬ﺳﻮرﻳﺎ ‪٢٠٠٥ -٢٠٠٤‬‬


‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﻟﻔﻬﺮﺱ ‪..‬‬
‫‪٣‬‬ ‫ﻣﻘﺪﻣﺔ ‪...............................................................................................‬‬

‫ﻏﺮﺿﯿﺔ اﻟﺘﻮﺟﺔ ﻓﻲ دﻟﻔﻲ ‪object-oriented in Delphi‬‬

‫‪٤‬‬ ‫اﻷﺻﻨﺎف واﻷﻏﺮاض ‪...............................................................................‬‬


‫‪٦‬‬ ‫ﺗﻌﺮﻳﻒ اﻷﺻﻨﺎف ﻓﻲ دﻟﻔﻲ ‪........................ .............................................‬‬
‫‪٨‬‬ ‫اﻟﺘﺤﻤﯿﻞ اﻟﺰاﺋﺪ ﻟﻠﻤﻨﺎھﺞ ‪.......................................... method overloading‬‬

‫ﻧﻈﺮة أﻛﺜﺮ ﺗﻔﺼﯿﻼ ﻓﻲ ﻏﺮﺿﯿﺔ اﻟﺘﻮﺟﺔ‬

‫‪٨‬‬ ‫اﻟﺘﻐﻠﯿﻒ ‪.............................. ............................................. Encapsulation‬‬


‫‪١١‬‬ ‫ﻣﺤﺪدات اﻟﻮﺻﻮل ‪........................................ Private, Protected, Public‬‬
‫‪١١‬‬ ‫اﻟﺘﻐﻠﯿﻒ ﺑﺈﺳﺘﺨﺪام اﻟﺨﺼﺎﺋﺺ ‪............................................. Properties‬‬
‫‪١٢‬‬ ‫ﺗﻌﺮﻳﻒ ﺧﺎﺻﯿﺔ ﺟﺪﻳﺪة ‪................................................................‬‬
‫‪١٤‬‬ ‫ﻣﺜﺎل ﻋﻤﻠﻲ ‪....................................... .............................................‬‬
‫‪٢١‬‬ ‫ﻣﻼﺣﻈﺎت ﺣﻮل اﻟﺨﺼﺎﺋﺺ ‪....................................................................‬‬

‫اﻟﻤﺰﻳﺪ ﻋﻦ اﻟﺘﻐﻠﯿﻒ‬
‫‪٢٢‬‬ ‫اﻟﺘﻐﻠﯿﻒ ﻣﻊ اﻷﺷﻜﺎل ‪.........................................................................‬‬

‫‪٢٣‬‬ ‫اﻟﺒﺎﻧﻲ ‪................................................................................ Constructor‬‬


‫‪٢٤‬‬ ‫ﺑﻨﺎء ﺑﺎﻧﻲ ﺟﺪﻳﺪ‪................................... .............................................‬‬
‫‪٢٥‬‬ ‫اﻟﮫﺎدم ‪ Destructor‬واﻟﻤﻨﮫﺞ ‪.............................................................. Free‬‬
‫‪٢٦‬‬ ‫ﻧﻤﻮذج ﻣﺮﺟﻌﯿـﺔ أﻏﺮاض دﻟﻔﻲ ‪....................................................................‬‬
‫‪٢٦‬‬ ‫ﻧﺴﺐ اﻷﻏﺮاض ‪...................................................................................‬‬
‫‪٢٧‬‬ ‫اﻷﻏﺮاض واﻟﺬاﻛﺮة ‪....................................................................................‬‬
‫‪٣٠‬‬ ‫ﺗﺤﺮﻳﺮ اﻷﻏﺮاض ﻣﺮة واﺣﺪة ﻓﻘﻂ ‪..................................................................‬‬

‫‪٣١‬‬ ‫اﻟﻮراﺛﺔ ﻣﻦ أﻧﻤﺎط ﻣﻮﺟﻮدة ‪..........................................................................‬‬


‫‪٣٢‬‬ ‫اﻟﺘﻐﻠﯿﻒ واﻟﺤﻘﻮل اﻟﻤﺤﻤﯿﺔ ‪..................... Protected Fields and Encapsulation‬‬
‫‪٣٣‬‬ ‫دﺧﻮل ﺑﯿﺎﻧﺎت ﻣﺤﻤﯿﺔ ﻟﺼﻨﻒ آﺧﺮ ‪................................... Protected Hack‬‬
‫‪٣٤‬‬ ‫ﺗﻄﺒﯿﻖ ﻋﻤﻠﻲ ‪......................................................................‬‬
‫‪٣٥‬‬ ‫اﻟﻮراﺛﺔ واﻟﺘﻮاﻓﻖ ﺑﯿﻦ اﻷﻧﻤﺎط ‪.......................................................................‬‬
‫‪٣٦‬‬ ‫اﻟﺘﺤﺪﻳﺪ اﻟﻤﺘﺄﺧﺮ وﺗﻌﺪدﻳﺔ اﻷﺷﻜﺎل ‪...............................................................‬‬
‫‪٣٨‬‬ ‫إﻋﺎدة ﺗﻌﺮﻳﻒ اﻟﻤﻨﺎھﺞ واﻟﻤﻨﺎھﺞ اﻟﻤﮫﯿﻤﻨﺔ ‪......................................................‬‬
‫‪٣٩‬‬ ‫اﻟﻤﻨﺎھﺞ اﻹﻓﺘﺮاﺿﯿﺔ ﻣﻘﺎﺑﻞ اﻟﺪﻳﻨﺎﻣﯿﻜﯿﺔ ‪…….……Virtual versus Dynamic Methods‬‬
‫‪٤٠‬‬ ‫اﻟﻤﻌﺎﻣﻼن ‪ IS‬و ‪.................................................................................. AS‬‬
‫‪٤٢‬‬ ‫إﺳﺘﺨﺪام اﻟﻮاﺟﮫﺎت ‪......................................................... Using Interfaces‬‬

‫‪٢‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺗﻌﺘﻤﺪ "ﺑﻴﺌﺔ ﺍﻟﺘﻄﻮﻳﺮ ﺩﻟﻔﻲ" ﻋﻠﻰ ﺍﻟﱪﳎﺔ ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟ‪‬ﻪ ‪ .‬ﺩﻟﻔﻲ ﻫﻲ ﺗﻮﺳﻴﻊ ﻟﻠﻐﺔ ﺍﻟﱪﳎﺔ ﺑﺎﺳﻜﺎﻝ ‪ ،‬ﻭﺍﻟﱵ ﻋﺮﻓﺖ ﺑﺈﺳﻢ‬
‫ﺑﺎﺳﻜﺎﻝ ﺍﻟﻐﺮﺿﻴﺔ )‪. (Object Pascal‬‬
‫ﻋﺰﻣﺖ ﺑﻮﺭﻻﻧﺪ ﻋﻠﻰ ﺍﻹﺷﺎﺭﺓ ﻟﻠﻐﺔ ﺑﺎﻹﺳﻢ )"ﺍﻟﻠﻐﺔ ﺩﻟﻔﻲ"( ﺃﻭ )"‪ ("The Delphi language‬ﻭﺇﻋﺘﺒﺎﺭﻫﺎ ﻟﻐﺔ ﻣﺴﺘﻘﻠﺔ ﺑﺪﻻ ﻣﻦ‬
‫ﺗﺴﻤﻴﺘﻬﺎ ﺑﻴﺌﺔ ﺍﻟﺘﻄﻮﻳﺮ ﺩﻟﻔﻲ )" ‪. ("Delphi development environment‬‬
‫ﺭﲟﺎ ﻳﻜﻮﻥ ﺫﻟﻚ ﻹﻥ ﺑﻮﺭﻻﻧﺪ ﺗﺮﻳﺪ ﺃﻥ ﺗﺼﺒﺢ ﻗﺎﺩﺭﺓ ﻋﻠﻰ ﺍﻟﻘﻮﻝ ﺑﺈﻥ ﻛﻴﻠﻜﺲ )‪ (Kylix‬ﺗﺴﺘﺨﺪﻡ ﺍﻟﻠﻐﺔ ﺩﻟﻔﻲ ‪ ،‬ﻛﻤﺎ ﺃ‪‬ﺎ‬
‫ﻭﻓﺮﺕ ﺩﻟﻔﻲ ﻟﻠﻌﻤﻞ ﲢﺖ ﻣﻨﺼﺔ ﻣﺎﻳﻜﺮﻭﺳﻮﻓﺖ ﺩﻭﺕ_ﻧﻴﺖ )‪ ، (Microsoft .NET platform‬ﻭﺭﲟﺎ ﻳﺴﻌﻨﺎ ﺍﻟﻘﻮﻝ ﺃﻥ ﺩﻟﻔﻲ‬
‫ﻣﻌﺮﻭﻓﺔ ﻛﻠﻐﺔ ﺑﺮﳎﺔ ﻣﺴﺘﻘﻠﺔ ﰲ ﺻﻒ ﺍﻟﻠﻐﺎﺕ ﺍﻷﻛﺜﺮ ﺷﻴﻮﻋﺎ ﰲ ﺍﻟﻌﺎﱂ ﻭﻟﻴﺴﺖ ﳎﺮﺩ ﺑﻴﺌﺔ ﺗﻄﻮﻳﺮ ﺗﻌﺘﻤﺪ ﺑﺎﺳﻜﺎﻝ ﺍﻟﻐﺮﺿﻴﺔ ‪.‬‬
‫ﻋﻠﻰ ﻛﻞ ﺣﺎﻝ ﺳﻮﺍﺀ ﻛﺎﻧﺖ "ﺑﻴﺌﺔ ﺍﻟﺘﻄﻮﻳﺮ ﺩﻟﻔﻲ " ﺃﻭ "ﺍﻟﻠﻐﺔ ﺩﻟﻔﻲ" ‪ ،‬ﻓﺈﻥ ﺍﻟﺮﻭﺡ ﻫﻲ ﻧﻔﺴﻬﺎ ﻟﻐﺔ ﺑﺮﳎﺔ ﻗﻮﻳﺔ ﻭﻣﺴﺘﻘﺮﺓ ﲤﻴﺰﻫﺎ‬
‫ﺇﻧﺘﺎﺟﻴﺘﻬﺎ ﺍﻟﻔﺮﻳﺪﺓ ‪.‬‬
‫ﻻ ﺃﻇﻦ ﺃﱐ ﺳﺄﻗﻒ ﻃﻮﻳﻼ ﺃﻣﺎﻡ ﻫﺬﺍ ﺍﳌﻮﺿﻮﻉ ﻭﺳﺄﺳﺘﺨﺪﻡ ﺍﻟﺘﺴﻤﻴﺔ ﺍﻟﱵ ﲣﺮﺝ ﻣﻌﻲ ﺃﻭﻻﹰ ‪.‬‬

‫ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ ﰲ ﺩﻟﻔﻲ ‪: object-oriented in Delphi‬‬

‫‪ ،‬ﺣﱴ ﺃﻥ ﻣﻘﺪﺍﺭ‬ ‫‪object-oriented programming‬‬ ‫ﺇﻥ ﻣﻌﻈﻢ ﺍﻟﻠﻐﺎﺕ ﺍﳊﺪﻳﺜﺔ ﺗﺪﻋﻢ ﺍﻟﱪﳎﺔ ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ )‪ (OOP‬ﺃﻭ‬
‫ﺩﻋﻢ ﺍﻟﻠﻐﺔ ﻟﻠـ ‪ OOP‬ﺃﺻﺒﺢ ﻳﻨﻈﺮ ﺇﻟﻴﺔ ﰲ ﻛﺜﲑ ﻣﻦ ﺍﻷﺣﻴﺎﻥ ﻛﻤﻘﻴﺎﺱ ﻳﻌﱪ ﻋﻦ ﺃﳘﻴﺔ ﺍﻟﻠﻐﺔ ‪.‬‬
‫ﺗﻌﺘﻤﺪ ﺍﻟﱪﳎﺔ ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ ﻋﻠﻰ ﺛﻼﺙ ﻣﻔﺎﻫﻴﻢ ﺃﺳﺎﺳﻴﺔ ﺳﻨﻌﺎﳉﻬﺎ ﰲ ﻫﺬﺍ ﺍﻟﻔﺼﻞ ‪:‬‬

‫‪ -‬ﺍﻟﺘﻐﻠﻴﻒ ‪. encapsulation‬‬
‫‪.‬‬ ‫‪ -‬ﺍﻟﻮﺭﺍﺛﺔ‬
‫‪inheritance‬‬
‫‪ -‬ﺗﻌﺪﺩﻳﺔ ﺍﻷﺷﻜﺎﻝ ‪. polymorphism‬‬

‫ﺩﻟﻔﻲ ﻫﻲ ﺗﻮﺳﻴﻊ ﻏﺮﺿﻲ_ﺍﻟﺘﻮﺟﺔ ﻟﻠﻐﺔ ﺑﺎﺳﻜﺎﻝ ﺍﻟﺘﻘﻠﻴﺪﻳﺔ ‪.‬ﻭﻣﺎ ﺃﺭﻳﺪ ﺍﻟﺘﻨﻮﻳﺔ ﺇﻟﻴﺔ ﻫﻨﺎ ﺃﻥ ﺍﻟﺼﻴﺎﻏﺔ ﺍﻟﻨﺤﻮﻳﺔ ﻟﻠﻐﺔ ﺍﻟﺒﺎﺳﻜﺎﻝ‬
‫ﻣﺸﻬﻮﺭﺓ ﺑﺈ‪‬ﺎ ﺻﻴﺎﻏﺔ ﺃﻛﺜﺮ ﻭﺿﻮﺣﺎ ﻭﻗﺎﺑﻠﻴﺔ ﻟﻠﻘﺮﺍﺀﺓ ﻣﻦ ﻣﻌﻈﻢ ﺍﻟﻠﻐﺎﺕ ﺍﻷﺧﺮﻯ )ﻭﻟﻨﻘﻞ ﻣﺜﻼ ﻟﻐﺔ ‪ ، ( C‬ﻭﺑﺎﻟﺘﺎﱄ ﻛﻤﻴﺔ ﺃﻛﱪ‬
‫ﻣﻦ ﺍﳊﺸﻮ ﻣﻦ ﺃﺟﻞ ﺍﳊﺼﻮﻝ ﻋﻠﻰ ﺷﻔﺮﺓ ﻣﻘﺮﻭﺀﺓ ﺗﺸﺒﺔ ﺍﻟﻜﻼﻡ ﺍﻟﻌﺎﺩﻱ ﲝﻴﺚ ﳝﻜﻦ ﻓﻬﻤﻬﺎ ﻭﺗﺬﻛﺮﻫﺎ ﺑﺸﻜﻞ ﺳﺮﻳﻊ ﻭﻣﻨﺘﻈﻢ‬
‫ﻭﻫﺬﺍ ﳑﺎ ﻳﻘﻞ ﻣﻦ ﺍﻟﻮﻗﻮﻉ ﺑﺎﻷﺧﻄﺎﺀ ‪.‬‬
‫ﻛﻤﺎ ﺃﻥ ﺍﻟﺘﻮﺳﻊ ﺍﻟﻐﺮﺿﻲ_ﺍﻟﺘﻮﺣﻪ ﳍﺬﺓ ﺍﻟﻐﺔ ﺑﺈﻋﺘﺮﺍﻑ ﺍﳉﻤﻴﻊ ﻻ ﻳﻘﻞ ﺃﳘﻴﺔ ﻋﻦ ﺍﳌﻮﺟﻮﺩ ﰲ ﺍﻟﻨﺴﻞ ﺍﳊﺎﱄ ﻟﻠﻐﺎﺕ ﺍﻟﱪﳎﺔ‬
‫ﺍﻟﻐﺮﺿﻴﺔ ﻣﻦ ‪ Java‬ﺣﱴ ‪. C#‬‬

‫‪٣‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﻷﺻﻨﺎﻑ ﻭﺍﻷﻏﺮﺍﺽ ‪:‬‬


‫ﺑﻨﻴﺖ ﺩﻟﻔﻲ ﺃﺳﺎﺳﺎﹰ ﻭﻓﻖ ﺗﺼﻮﺭ ﺍﻟﱪﳎﺔ ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ ‪ ،‬ﻭﺑﺸﻜﻞ ﺧﺎﺹ ﻋﻠﻰ ﺗﻌﺮﻳﻒ ﺃﳕﺎﻁ ﻷﺻﻨﺎﻑ ﺟﺪﻳﺪﺓ ‪.‬‬
‫ﻭﻋﻠﻴﻚ ﺃﻥ ﺗﻌﻠﻢ ﺃﻥ ﻛﻞ ﺷﻲﺀ ﰲ ﺩﻟﻔﻲ ﻳﺘﻢ ﺍﻟﺘﻌﺎﻣﻞ ﻣﻌﺔ ﻭﻓﻖ ﻫﺬﺍ ﺍﳌﻔﻬﻮﻡ ‪ ،‬ﺣﱴ ﻟﻮ ﻛﻨﺖ ﻻﺗﺸﻌﺮ ﺑﺬﻟﻚ ﺩﺍﺋﻤﺎ ‪ .‬ﻓﺈﺫﺍ ﻗﻤﺖ‬
‫ﻣﺜﻼﹰ ﺑﺈﻧﺸﺎﺀ ﺷﻜﻞ ﺟﺪﻳﺪ )‪ ، (Form‬ﻓﺈﻥ ﺩﻟﻔﻲ ﺳﺘﻘﻮﻡ ﺃﻭﺗﻮﻣﺎﺗﻴﻜﻴﺎ ﺑﺘﻌﺮﻳﻒ ﺻﻨﻒ ﺟﺪﻳﺪ ﻣﻦ ﺃﺟﻠﺔ ‪.‬‬

‫ﻭﻣﻦ ﺍﳌﻬﻢ ﺃﻥ ﺗﻔﻬﻢ ﺃﻥ ﻛﻞ ﻣﻜﻮﻥ ﰎ ﻭﺿﻌﺔ ﻋﻠﻰ ﺍﻟﺸﻜﻞ ﻫﻮ ﻋﺒﺎﺭﺓ ﻏﺮﺽ ‪ ،‬ﻭﻫﺬﺍ ﺍﻟﻐﺮﺽ ﺧﺎﺹ ﺑﺼﻨﻒ ﻣﻌﲔ ‪...‬‬

‫ﺗﻮﺿﻴﺢ ‪:‬‬
‫ﺍﳌﺼﻄﻠﺤﺎﻥ ﻏﺮﺽ ﻭﺻﻨﻒ ﻳﺴﺘﺨﺪﻣﺎﻥ ﺑﻜﺜﺮﺓ ‪ ،‬ﻭﻛﺜﲑﺍ ﻣﺎ ﻳﺘﻢ ﺇﺳﺎﺀﺓ ﻓﻬﻤﻬﻤﺎ ‪ ،‬ﺃﻛﺎﺩﳝﻴﺎ ﻧﺴﺘﻄﻴﻊ ﺍﻟﻘﻮﻝ ﺃﻥ ‪:‬‬
‫ﺍﻟﺼﻨﻒ ‪ :‬ﻫﻮ ﳕﻂ ﻣﻌﻄﻴﺎﺕ ﻣﻌﺮﻑ ﳝﻠﻚ ﺑﻌﺾ ﺍﻟﺘﻮﺻﻴﻔﺎﺕ ‪ ،‬ﻭﺑﻌﺾ ﺍﻟﻌﻤﻠﻴﺎﺕ " ﺍﻟﺘﺼﺮﻓﺎﺕ" )ﺃﻭ ﻣﺎ ﻳﺴﻤﻰ ﻣﻨﺎﻫﺞ( ‪.‬‬
‫ﺍﻟﻐﺮﺽ ‪ :‬ﻫﻮ ﻣﻨﺘﺴﺦ ﻣﻦ ﺍﻟﺼﻨﻒ ‪) ،‬ﺃﻭ ﻣﺘﻐﲑ ﻣﻦ ﳕﻂ ﻣﻌﻄﻴﺎﺕ ﺻﻨﻒ ( ‪ .‬ﲝﻴﺚ ﳝﻠﻚ ﻗﻴﻢ ﻟﻜﻞ ﺍﻟﺘﻮﺻﻴﻔﺎﺕ ﺍﻟﱵ ﳛﺪﺩﻫﺎ‬
‫ﺍﻟﺼﻨﻒ ‪ ،‬ﻭﳝﻜﻨﺔ ﺇﺳﺘﻌﻤﺎﻝ ﻋﻤﻠﻴﺎﺗﻪ ﻭﳜﻀﻊ ﻟﺘﺼﺮﻓﺎﺗﺔ ﻭﺧﻮﺍﺻﺔ ‪..،‬‬

‫ﺩﻋﻨﺎ ﻧﻀﺮﺏ ﻣﺜﻼ ﻣﻦ ﺍﻟﻄﺒﻴﻌﺔ ﻋﻠﻰ ﻫﺬﺍ ﺍﳌﻮﺿﻮﻉ ‪:‬‬


‫ﰲ ﺣﺎﻟﺔ ﺍﻹﻧﺴﺎﻥ ﻣﺜﻼ ‪ ،‬ﺇﻧﻨﺎ ﻋﻨﺪﻣﺎ ﻧﻘﻮﻝ ﺇﻧﺴﺎﻥ ))ﺑﺸﻜﻞ ﻋﺎﻡ (( ﻓﻨﺤﻦ ﻧﺪﻝ ﻋﻠﻰ ﺍﻟﺼﻨﻒ ﺇﻧﺴﺎﻥ ‪ .‬ﺃﻱ ﺍﻹﻧﺴﺎﻥ ﻫﻮ ﺍﻟﺼﻨﻒ‬
‫‪ ،‬ﻭﺃﺻﺒﺤﻨﺎ ﻧﻌﺮﻑ ﺑﻌﺾ ﺍﻟﺘﻮﺻﻴﻔﺎﺕ )ﺍﳋﺼﺎﺋﺺ( ﺍﳌﺘﻌﻠﻘﺔ ﺑﺔ ‪ ،‬ﻣﺜﻼ ﺃﻥ ﻟﻪ ﺇﺳﻢ ﳝﻴﺰﺓ ﻭ ﻃﻮﻝ ﻭﻭﺯﻥ ﻭﻟﻮﻥ ﻋﻴﻮﻥ ﻭﺃﻧﺔ ﻳﻘﻮﻡ‬
‫ﺑﺒﻌﺾ ﺍﻟﺴﻠﻮﻛﻴﺎﺕ )ﺍﳌﻨﺎﻫﺞ( ﻣﺜﻞ ﺍﻷﻛﻞ ﻭﺍﻟﺸﺮﺏ ﻭﺍﻟﺮﻛﺾ ﻭﺍﻟﻜﻼﻡ ‪ ،‬ﺗﺬﻛﺮ ﺃﻧﺔ ﻋﻨﺪﻣﺎ ﻧﺘﺤﺪﺙ ﻋﻦ ﺍﻟﺼﻨﻒ ﺇﻧﺴﺎﻥ ﻓﻨﺤﻦ‬
‫ﻻﳓﺪﺩ ﺃﻱ ﻗﻴﻤﺔ ﺛﺎﺑﺘﺔ ﻷﻱ ﻣﻦ ﺧﺼﺎﺋﺼﺔ ﻣﺜﻼ ﻻﳚﻮﺯ ﺍﻟﻘﻮﻝ ﺃﻥ ﻃﻮﻝ ﺍﻹﻧﺴﺎﻥ ﻫﻮ ‪ ١٧٥,٣‬ﻣﺘﺮ ﺩﻭﻣﺎ ﺃﻭ ﺣﺘﻤﺎ ‪....‬‬
‫ﺇﺫﺍ ﻛﺎﻥ ﺍﻹﻧﺴﺎﻥ ﻫﻮ ﺍﻟﺼﻨﻒ ﻓﻤﺎ ﻫﻮ ﺍﻟﻐﺮﺽ ﺇﺫﺍ ‪ ،‬ﺍﻟﻐﺮﺽ ﳚﺐ ﺃﻥ ﻳﻜﻮﻥ ﺣﺎﻟﺔ ﻣﻦ ﺣﺎﻻﺕ ﺍﻟﺼﻨﻒ ‪ ،‬ﺣﺎﻟﺔ ﻭﺍﺣﺪﺓ ﳏﺪﺩﺓ‬
‫ﺟﻴﺪﺍ ﻭﺗﻌﻄﻲ ﺍﻷﺟﻮﺑﺔ ﻭﺍﻟﻘﻴﻢ ﺍﻟﺪﻗﻴﻘﺔ ﻟﻜﻞ ﺍﻟﺼﻔﺎﺕ ﺍﳌﺘﻌﻠﻖ ﺑﺎﻟﺼﻨﻒ ﺍﻟﺘﺎﺑﻌﺔ ﻟﻪ ‪،‬‬
‫ﺍﻟﻐﺮﺽ ﰲ ﻫﺬﺓ ﺍﳊﺎﻟﺔ ﻫﻮ ﺇﻧﺴﺎﻥ ﻣﺎ ‪ ،‬ﺃﻱ ﺇﻧﺴﺎﻥ ﳏﺪﺩ ‪ ،‬ﻭﻟﻨﻘﻞ ﻋﺮﻭﺓ ﻋﻴﺴﻰ ‪،‬‬
‫ﺍﻟﻐﺮﺽ ﻋﺮﻭﺓ ﻣﻦ ﺍﻟﺼﻨﻒ ﺇﻧﺴﺎﻥ ﳝﻠﻚ ﲨﻴﻊ ﺧﻮﺍﺹ ﺍﻹﻧﺴﺎﻥ ﻭﻳﺄﺧﺬ ﻗﻴﻢ ﳏﺪﺩﺓ ﳍﺎ ‪ ،‬ﺍﻹﺳﻢ ﻋﺮﻭﺓ ‪ ،‬ﺍﻟﻄﻮﻝ ‪ ١٨٢,٣‬ﻣﺘﺮ ‪،‬‬
‫ﺍﻟﻮﺯﻥ ‪٨٥‬ﻛﻎ ‪ ،‬ﻟﻮﻥ ﺍﻟﻌﻴﻨﲔ ﺑﲏ ‪ ...‬ﺍﱁ ‪ ...‬ﻭﻳﺴﺘﻄﻴﻊ ﺗﻨﻔﻴﺬ ﻛﻞ ﻣﻦ ﻣﻨﺎﻫﺠﺔ )ﺳﻠﻮﻛﻴﺎﺗﺔ( ﻣﱴ ﺷﺎﺀ ﻣﻦ ﺍﻟﺮﻛﺾ ﻭﺍﻷﻛﻞ‬
‫ﻭﺍﻟﻜﻼﻡ ﺍﱁ ‪..‬‬
‫ﻭﺑﺎﻟﺘﺎﱄ ﻟﻠﺼﻨﻒ ﺇﻧﺴﺎﻥ ﻋﺪﺩ ﻛﺒﲑ ﻣﻦ ﺍﻷﻏﺮﺍﺽ ﻣﺜﻞ ﻋﺮﻭﺓ ﻭﻛﻤﺎﻝ ﻭﻋﻼﺀ ﻭﻋﺼﺎﻡ ﻭﻋﻠﻲ ﺍﱁ‪ ....‬ﻭﻛﻞ ﻣﻨﻬﻢ ﳝﻠﻚ ﺻﻔﺎﺕ‬
‫ﺍﻟﺼﻨﻒ ﺍﻷﺳﺎﺳﻴﺔ ﻣﻦ ﺃﺟﻞ ﻗﻴﻢ ﳏﺪﺩﺓ ﺧﺎﺻﺔ ﺑﻪ ﻫﻮ ‪....‬‬

‫ﺃﲤﲎ ﺃﻥ ﻳﻜﻮﻥ ﺍﻷﻣﺮ ﺃﺻﺒﺢ ﻭﺍﺿﺤﺎ ﺍﻵﻥ ‪.‬‬

‫‪٤‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫‪ -‬ﻛﺜﲑﺍﹰ ﻣﺎ ﻳﺸﺎﺭ ﺇﱃ ﺍﻷﻏﺮﺍﺽ ﺑﺎﻟﻜﻴﺎﻧﺎﺕ )‪. (entities‬‬

‫ﺍﻟﻌﻼﻗﺔ ﺑﲔ ﺍﻟﻐﺮﺽ )‪ (object‬ﻭ ﺍﻟﺼﻨﻒ)‪ (class‬ﻫﻲ ﻧﻔﺴﻬﺎ ﺍﻟﻌﻼﻗﺔ ﺑﲔ ﺍﳌﺘﺤﻮﻝ)‪ (variable‬ﻭﺍﻟﻨﻤﻂ )‪. (type‬‬

‫; ‪A : integer‬‬ ‫ﺣﻴﺚ‬ ‫‪A‬‬ ‫ﻭﺍﳌﺘﺤﻮﻝ‬ ‫‪Integer‬‬ ‫ﻣﺜﻼ ﻫﻲ ﺍﻟﻌﻼﻗﺔ ﺑﲔ‬

‫ﺩﻋﻨﺎ ﻧﻮﺿﺢ ﺑﻌﺾ ﺍﳌﺴﺎﺋﻞ ﺍﳌﻬﻤﺔ ﻫﻨﺎ ‪:‬‬

‫ﺇﻥ ﻣﺘﺤﻮﻝ ﻣﻦ ﳕﻂ ﺻﻨﻒ ﻣﻌﲔ ﰲ ﺩﻟﻔﻲ ﻛﻤﺎ ﻫﻮ ﺍﳊﺎﻝ ﰲ ﻣﻌﻈﻢ ﻟﻐﺎﺕ ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ ﻟﻦ ﳝﺜﻞ ﲣﺰﻳﻨﺎ ﻟﻠﻐﺮﺽ ﰲ‬
‫ﺍﻟﺬﺍﻛﺮﺓ ﺿﻤﻦ ﻫﺬﺍ ﺍﳌﺘﺤﻮﻝ ‪ ،‬ﻭﻟﻜﻨﺔ ﻓﻘﻂ ﻋﺒﺎﺭﺓ ﻋﻦ ﻣﺆﺷﺮ ﺇﱃ ﺍﻟﻐﺮﺽ ﰲ ﺍﻟﺬﺍﻛﺮﺓ ‪.‬‬

‫ﻭﺑﻨﺎﺀ ﻋﻠﻰ ﺫﻟﻚ ﻓﺈﻧﻨﺎ ﻻ ﻧﺴﺘﻄﻴﻊ ﺍﻟﺘﻌﺎﻣﻞ ﻣﺒﺎﺷﺮﺓ ﻣﻊ ﺍﻷﻏﺮﺍﺽ ﻛﻤﺎ ﻧﺘﻌﺎﻣﻞ ﻣﻊ ﺍﳌﺘﺤﻮﻻﺕ ﺍﻟﻌﺎﺩﻳﺔ ‪ ،‬ﻹﻥ ﺍﻷﻏﺮﺍﺽ ﻟﻦ ﲣﺰﻥ‬
‫ﰲ ﺫﺍﻛﺮﺓ ﺍﳌﺘﺤﻮﻝ ﺍﳌﻌﺮﻑ ﳍﺎ ﻛﻤﺎ ﳛﺪﺙ ﰲ ﺣﺎﻟﺔ ﻣﺘﺤﻮﻝ ﻋﺎﺩﻱ ‪ ،‬ﺑﻞ ﻫﻲ ﲝﺎﺟﺔ ﺇﱃ ﺣﺠﺰ ﻳﺪﻭﻱ ﳌﺴﺎﺣﺔ ﺫﺍﻛﺮﺓ ﺧﺎﺻﺔ‬
‫‪‬ﺎ ﻭﻣﻦ ﰒ ﻳﺼﺒﺢ ﺍﳌﺘﺤﻮﻝ ﺍﳋﺎﺹ ‪‬ﺎ ﻳﺆﺷﺮ ﻋﻠﻰ ﻫﺬﺓ ﺍﳌﺴﺎﺣﺔ ‪ ،‬ﺃﻱ ﳜﺰﻥ ﻋﻨﻮﺍﻥ ﻫﺬﺓ ﺍﳌﺴﺎﺣﺔ ﻓﻘﻂ ‪ ،‬ﻭﻻﳜﺰﻥ ﺑﻴﺎﻧﺎﺕ‬
‫ﺍﻟﻐﺮﺽ ﺿﻤﻨﺔ‪..‬‬

‫ﺇﺫﻥ ﻭﺟﺪﻧﺎ ﺍﻵﻥ ﻓﺮﻗﺎ ﻣﻬﻤﺎ ﺑﲔ ﻃﺮﻳﻘﺔ ﺍﻟﺘﻌﺎﻣﻞ ﻣﻊ ﺍﳌﺘﺤﻮﻻﺕ ﺍﻟﻌﺎﺩﻳﺔ ﻭﻣﻊ ﺍﻷﻏﺮﺍﺽ ‪ ،‬ﻭﻗﻠﻨﺎ ﺃﻧﺔ ﳚﺐ ﺣﺠﺰ )ﺇﻧﺸﺎﺀ( ﺫﺍﻛﺮﺓ‬
‫ﻟﻠﻐﺮﺽ ﻗﺒﻞ ﺇﺳﺘﺨﺪﺍﻣﺔ ‪ ،،،‬ﻛﻴﻒ ﻳﺘﻢ ﺫﻟﻚ ؟‬

‫ﻳﺘﻢ ﺫﻟﻚ ﺑﺈﺣﺪﻯ ﻃﺮﻳﻘﺘﲔ ‪:‬‬

‫‪ -١‬ﺇﻧﺸﺎﺀ ﻭﺣﺠﺰ ﺍﻟﺬﺍﻛﺮﺓ ﻳﺪﻭﻳﺎ ﻟﻐﺮﺽ ﻣﻦ ﺻﻨﻒ ﻣﺎ ‪ ) ..‬ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﳌﻨﻬﺞ ﺍﻟﺒﺎﱐ ‪(Create‬‬

‫‪ -٢‬ﺃﻭ ﻧﺴﺐ ﺍﻟﻐﺮﺽ ﺇﱃ ﻏﺮﺽ ﻣﻮﺟﻮﺩ ﰎ ﺣﺠﺰ ﺍﻟﺬﺍﻛﺮﺓ ﻟﻪ ﻣﺴﺒﻘﺎ ‪) ..‬ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﻟﻨﺴﺐ =‪( :‬‬

‫‪var‬‬
‫;‪Obj1, Obj2: TClass‬‬
‫‪begin‬‬
‫‪// assign a newly created object‬‬
‫;‪Obj1 := TMyClass.Create‬‬
‫‪// assign to an existing object‬‬
‫;‪Obj2 := Obj1‬‬

‫‪٥‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﰲ ﻫﺬﺍ ﺍﳌﺜﺎﻝ ﻗﻤﻨﺎ ﺑﺘﻌﺮﻳﻒ ﻏﺮﺿﲔ ‪ Obj1, Obj2‬ﻣﻦ ﺍﻟﺼﻨﻒ ‪ ، Tclass‬ﺍﻟﻐﺮﺽ ﺍﻷﻭﻝ ‪ obj1‬ﻗﻤﻨﺎ ﺑﺈﻧﺸﺎﺀﺓ ﺑﺎﻟﻄﺮﻳﻘﺔ‬
‫ﺍﻷﻭﱃ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﳌﻨﻬﺞ ﺍﳌﻬﻢ ﻭﺍﻟﺸﺎﺋﻊ ‪ Create‬ﺍﻟﺬﻱ ﳛﺠﺰ ﺍﻟﺬﺍﻛﺮﺓ ﻟﺔ ﻭﻳﻬﻴﺌﺔ ﻟﻺﺳﺘﺨﺪﺍﻡ ‪.‬ﻭﺍﻟﻐﺮﺽ ﺍﻟﺜﺎﱐ ‪ obj2‬ﻗﻤﻨﺎ‬
‫ﺑﻨﺴﺒﺔ ﺇﱃ ﻏﺮﺽ ﻣﻮﺟﻮﺩ ﻣﺴﺒﻘﺎ ﻭﻫﻮ ‪ ، Obj1‬ﻭﻛﻼ ﺍﻟﻄﺮﻳﻘﺘﲔ ﺻﺤﻴﺤﺘﲔ ﻭﻣﺴﺘﺨﺪﻣﺘﲔ ‪.‬‬

‫ﻣﻬﻢ ‪ :‬ﲟﺎ ﺃﻧﻨﺎ ﻗﻤﻨﺎ ﲝﺠﺰ ﺍﻟﺬﺍﻛﺮﺓ ﻳﺪﻭﻳﺎ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﳌﻨﻬﺞ ‪ ، Create‬ﻓﺈﻧﺔ ﻳﺘﻮﺟﺐ ﻋﻠﻴﻨﺎ ﲢﺮﻳﺮﻫﺎ ﻳﺪﻭﻳﺎ ﺃﻳﻀﺎﹰ ‪ ،‬ﻭﻳﺘﻢ ﺫﻟﻚ‬
‫ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﳌﻨﻬﺞ ‪ . Free‬ﺳﻨﻠﻘﻲ ﻧﻈﺮﺓ ﺗﻔﺼﻴﻠﻴﺔ ﻋﻠﻰ ﻫﺬﻳﻦ ﺍﳌﻨﻬﺠﲔ ﰲ ﻫﺬﺍ ﺍﻟﺒﺤﺚ ‪.‬‬

‫‪ (Finaly ....‬ﻟﺘﻌﺮﻳﻒ ﺍﻷﺻﻨﺎﻑ ﻭﲢﺮﻳﺮﻫﺎ ‪،‬‬ ‫)‪Try‬‬ ‫ﺃﻧﺼﺤﻚ ﺑﺈﺳﺘﺨﺪﺍﻡ ﻣﻌﺎﳉﺔ ﺍﻹﺳﺘﺜﻨﺎﺀﺍﺕ‬

‫ﻛﺬﻟﻚ ﻓﺈﻥ ﻣﻌﺎﳉﺔ ﺍﻹﺳﺘﺜﻨﺎﺀﺍﺕ ﺳﻨﺘﺤﺪﺙ ﻋﻨﻬﺎ ﻻﺣﻘﺎ ‪ ،‬ﺇﻥ ﱂ ﻳﻜﻦ ﻟﺪﻳﻚ ﺗﺼﻮﺭ ﻭﺍﺿﺢ ﻋﻨﻬﺎ ﺑﻌﺪ ‪.‬‬

‫ﺗﻌﺮﻳﻒ ﺍﻷﺻﻨﺎﻑ ﰲ ﺩﻟﻔﻲ ‪:‬‬

‫ﻟﺘﻌﺮﻳﻒ ﺻﻨﻒ ﺟﺪﻳﺪ ﰲ ﺩﻟﻔﻲ ‪ ،‬ﺩﻋﻨﺎ ﻧﺘﺬﻛﺮ ﺃﻥ ﺍﻟﺼﻨﻒ ﳛﻮﻱ ﺷﻴﺌﲔ ﻣﻬﻤﲔ ﳘﺎ ﺍﳊﻘﻮﻝ )ﺑﻴﺎﻧﺎﺕ ﺍﻟﺼﻨﻒ( ﻭﺍﳌﻨﺎﻫﺞ‬
‫)ﻋﻤﻠﻴﺎﺕ ﺍﻟﺼﻨﻒ( ‪.‬‬

‫ﺑﻨﺎﺀ ﺻﻨﻒ ﺟﺪﻳﺪ ﻣﻮﺿﻮﻉ ﺳﻬﻞ ﰲ ﺩﻟﻔﻲ ‪.‬‬

‫ﺇﺫﺍ ﻓﻜﺮﻧﺎ ﺑﻨﺎﺀً ﻋﻠﻰ ﻣﺎ ﺳﺒﻖ ﻣﺎﺫﺍ ﳓﺘﺎﺝ ﻟﻨﻌﺮﻑ ﺻﻨﻒ ﺟﺪﻳﺪ ‪ ،‬ﻟﻮﺟﺪﻧﺎ ﺃﻧﻨﺎ ﻧﺮﻳﺪ ﺗﻌﺮﻳﻒ ﺍﳊﻘﻮﻝ ﺍﻟﱵ ﳛﻮﻳﻬﺎ ﻫﺬﺍ ﺍﻟﺼﻨﻒ‬
‫ﻭﺍﻟﻌﻤﻠﻴﺎﺕ ﺍﻟﱵ ﻳﺴﺘﻄﻴﻊ ﺇﳒﺎﺯﻫﺎ ‪ ،‬ﻭﺑﺎﻟﺘﺄﻛﻴﺪ ﻧﻌﺮﻑ ﻟﻪ ﺇﲰﺎ ﻓﺮﻳﺪﺍ ﺧﺎﺹ ﺑﻪ ‪.‬‬

‫ﺍﳊﻘﻮﻝ ﻫﻲ ﻋﺒﺎﺭﺓ ﻋﻦ ﻣﺘﺤﻮﻻﺕ ﻋﺎﺩﻳﺔ ‪ ،‬ﻭﺍﻟﻌﻤﻠﻴﺎﺕ ﻫﻲ ﻋﺒﺎﺭﺓ ﻋﻦ ﻣﻨﺎﻫﺞ )ﺃﻱ ﺗﻮﺍﺑﻊ ﺃﻭ ﺇﺟﺮﺍﺀﺍﺕ( ‪ .‬ﺗﻨﺴﻴﻖ ﻫﺬﺍ ﺍﻟﺘﻌﺮﻳﻒ‬
‫ﻳﺘﻢ ﺑﺼﻮﺭﺓ ﺑﺴﻴﻄﺔ – ﺑﺈﻥ ﻧﺬﻛﺮ ﰲ ﻗﺴﻢ ‪ Type‬ﺇﺳﻢ ﺍﻟﺼﻨﻒ ﳏﺪﺩﺍﹰ ﺑﺎﻟﻜﻠﻤﺔ ﺍﳌﻔﺘﺎﺣﻴﺔ ‪ Class‬ﻭﻧﺘﺒﻌﻪ ﻣﺒﺎﺷﺮﺓ ﺑﺘﻌﺮﻳﻒ‬
‫ﺍﳊﻘﻮﻝ ﺍﳋﺎﺻﺔ ﺑﻪ ‪ ،‬ﰒ ﺭﺅﻭﺱ ﺍﳌﻨﺎﻫﺞ ﺍﻟﱵ ﻳﻌﺮﻓﻬﺎ ‪ ،‬ﻭﺑﺎﻟﺘﺄﻛﻴﺪ ﻧﻨﻬﻲ ﺫﻟﻚ ﺑـ ;‪: End‬‬

‫‪Type‬‬
‫‪TDate = class‬‬
‫;‪Month, Day, Year: Integer‬‬
‫;)‪procedure SetValue (m, d, y: Integer‬‬
‫ﳛﺪد إذا ﻛﺎﻧﺖ اﻟﺴﻨﺔ ﻛﺒﯿﺴﺔ ‪function LeapYear: Boolean; //‬‬
‫;‪end‬‬

‫‪٦‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻣﻼﺣﻈﺔ ‪:‬‬

‫ﺇﻥ ﺍﻟﺒﺎﺩﺋﺔ ‪ T‬ﺍﻟﱵ ﺳﺒﻘﻨﺎ ‪‬ﺎ ﺇﺳﻢ ﺍﳌﺘﺤﻮﻝ ﻫﻲ ﻋﺒﺎﺭﺓ ﻋﻦ ﺗﻘﻠﻴﺪ )ﻋﺮﻑ( ﻟﻠﻤﺘﺮﺟﻢ ‪ ،‬ﻳﺘﺒﻌﺔ ﻣﱪﳎﻮ ﺍﻟﺪﻟﻔﻲ ﻣﻨﺬ ﻇﻬﻮﺭﻫﺎ ﺑﺈﻳﻌﺎﺫ‬
‫ﻣﻦ ﺷﺮﻛﺔ ﺑﻮﺭﻻﻧﺪ ﻧﻔﺴﻬﺎ ‪ .‬ﺍﳊﺮﻑ ‪ T‬ﻫﻮ ﺇﺧﺘﺼﺎﺭ ﻟـ‪ ، Type‬ﻭﻫﻮ ﳎﺮﺩ ﺣﺮﻑ ﻭﻟﻜﻦ ﺇﺗﺒﺎﻉ ﻫﺬﺍ ﺍﻟﻌﺮﻑ ﺳﻴﺠﻌﻞ‬
‫ﺷﻔﺮﺗﻚ ﻣﻔﻬﻮﻣﺔ ﺃﻛﺜﺮ ﻣﻦ ﻗﺒﻞ ﺑﻘﻴﺔ ﺍﳌﻄﻮﺭﻳﻦ ﺍﻟﺬﻳﻦ ﺍﻋﺘﺎﺩﻭ ﻋﻠﻰ ﺫﻟﻚ ‪.‬‬

‫ﺭﲟﺎ ﻻﺣﻈﺖ ﻣﻦ ﺗﻌﺮﻳﻒ ﺍﻟﺼﻨﻒ ﺃﻧﻨﺎ ﻗﻤﻨﺎ ﺑﺘﻌﺮﻳﻒ ﺃﲰﺎﺀ ﺍﻟﺘﻮﺍﺑﻊ ﻭﺍﻹﺟﺮﺍﺀﺍﺕ ﻓﻘﻂ )ﺭﺅﻭﺱ ﺍﳌﻨﺎﻫﺞ( ﻭﱂ ﻧﻘﻢ ﺑﻜﺘﺎﺑﺔ‬
‫ﺃﺟﺴﺎﻣﻬﺎ ﻫﻨﺎﻙ ‪ ،‬ﺣﻴﺚ ﻧﻘﻮﻡ ﺑﺘﻌﺮﻳﻒ ﺃﺟﺴﺎﻡ ﺍﳌﻨﺎﻫﺞ )ﺗﻮﺍﺑﻊ‪+‬ﺇﺟﺮﺍﺀﺍﺕ( ﰲ ﺟﺴﻢ ﺍﻟﻮﺣﺪﺓ ﻧﻔﺴﻬﺎ ‪ ،‬ﺃﻱ ﻗﺴﻢ ﺍﻟـ‬
‫‪ Implementation‬ﺍﳋﺎﺹ ‪‬ﺎ ‪.‬‬

‫ﻭﲟﺎ ﺃﻧﻨﺎ ﻧﺴﺘﻄﻴﻊ ﺗﻌﺮﻳﻒ ﺃﻛﺜﺮ ﻣﻦ ﺻﻨﻒ ﰲ ﺍﻟﻮﺣﺪﺓ )‪ (Unit‬ﻭﻟﻜﻞ ﺻﻨﻒ ﻣﻨﺎﻫﺞ ﺧﺎﺻﺔ ﺑﻪ ﻟﺬﻟﻚ ﳚﺐ ﲤﻴﻴﺰ ﺟﺴﻢ ﻛﻞ‬
‫ﻣﻨﻬﺞ ﻟﻨﻌﺮﻑ ﻹﻱ ﺻﻨﻒ ﻳﺘﺒﻊ ‪ .‬ﻣﻦ ﺃﺟﻞ ﺫﻟﻚ ﻓﺈﻥ ﺗﻌﺮﻳﻒ ﺃﺟﺴﺎﻡ ﺍﳌﻨﺎﻫﺞ ﻳﺴﺒﻖ ﺑﺈﺳﻢ ﺍﻟﺼﻨﻒ ﻣﻔﺼﻮﻻ ﺑﻨﻘﻄﺔ ﻋﻦ ﺇﺳﻢ‬
‫ﺍﳌﻨﻬﺞ ﻣﺜﻼ ‪: TDate.SetValue‬‬

‫‪Implementation‬‬

‫…‬

‫;)‪procedure TDate.SetValue (m, d, y: Integer‬‬


‫‪begin‬‬
‫;‪Month := m‬‬
‫;‪Day := d‬‬
‫;‪Year := y‬‬
‫;‪end‬‬

‫;‪function TDate.LeapYear: Boolean‬‬


‫‪begin‬‬
‫‪// call IsLeapYear in SysUtils.pas‬‬
‫;)‪Result := IsLeapYear (Year‬‬
‫;‪end‬‬

‫ﻓﻜﺮﺓ ‪:‬‬

‫ﺇﺫﺍ ﺿﻐﻄﺖ ‪ Ctrl+Shift+C‬ﻋﻨﺪﻣﺎ ﻳﻜﻮﻥ ﺍﳌﺆﺷﺮ ﺿﻤﻦ ﺗﻌﺮﻳﻒ ﺍﻟﺼﻨﻒ ‪ ،‬ﻓﺈﻥ ﻣﻴﺰﺓ ﺗﻜﻤﻴﻞ ﺍﻟﺘﻌﺮﻳﻒ ﰲ ﺩﻟﻔﻲ ﺳﻮﻑ ﺗﻘﻮﻡ‬
‫ﺗﻠﻘﺎﺋﻴﺎ ﲟﺴﺎﻋﺪﺗﻚ ﻭﺗﻮﻟﻴﺪ ﻫﻴﻜﻞ ﺍﻟﺘﻌﺮﻳﻒ ﺍﳋﺎﺹ ﺑﺎﳌﻨﺎﻫﺞ ﺍﻟﱵ ﻗﻤﺖ ﺑﺘﻌﺮﻳﻔﻬﺎ ﰲ ﺍﻟﺼﻨﻒ ‪.‬‬

‫ﻋﺮﻓﻨﺎ ﺍﻵﻥ ﻛﻴﻒ ﻧﺒﲏ ﺻﻨﻒ ﺟﺪﻳﺪ ‪ ،‬ﻭﺃﻧﻨﺎ ﻧﺴﺘﻄﻴﻊ ﺃﻥ ﻧﻨﺸﻲﺀ ﺃﻏﺮﺍﺿﺎﹰ ﻣﻦ ﻫﺬﺍ ﺍﻟﺼﻨﻒ ﻭﺇﺳﺘﺨﺪﺍﻣﻬﺎ ﰲ ﺷﻔﺮﺗﻨﺎ ‪.‬‬

‫‪٧‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻣﺜﺎﻝ ﻋﻠﻰ ﺫﻟﻚ ‪:‬‬

‫‪var‬‬
‫;‪ADay: TDate‬‬
‫‪begin‬‬
‫‪// create an object‬‬
‫;‪ADay := TDate.Create‬‬
‫‪try‬‬
‫‪// use the object‬‬
‫;)‪ADay.SetValue (1, 1, 2000‬‬
‫‪if ADay.LeapYear then‬‬
‫;))‪ShowMessage ('Leap year: ' + IntToStr (ADay.Year‬‬
‫‪finally‬‬
‫‪// destroy the object‬‬
‫;‪ADay.Free‬‬
‫;‪end‬‬
‫;‪end‬‬

‫ﻻﺣﻆ ﺃﻥ ﺍﻟﺘﻌﺒﲑ ‪ ADay.LeapYear‬ﻣﺸﺎﺑﺔ ﲤﺎﻣﺎ ﻟﻠﺘﻌﺒﲑ ‪ . ADay.Year‬ﻣﻊ ﺃﻥ ﺇﺣﺪﺍﳘﺎ ﻫﻮ ﺗﺎﺑﻊ ﻟﻠﺘﻨﻔﻴﺬ ‪ ،‬ﻭﺍﻵﺧﺮ ﻫﻮ‬
‫ﻣﺘﺤﻮﻝ )ﻭﺻﻮﻝ ﺑﻴﺎﻧﺎﺕ ﻣﺒﺎﺷﺮ( ‪ ،‬ﺃﻱ ﻧﺼﻞ ﻟﺒﻴﺎﻧﺎﺕ ﺍﻟﻐﺮﺽ ﺑﻨﻔﺲ ﻃﺮﻳﻘﺔ ﺍﻟﻮﺻﻮﻝ ﳌﻨﺎﻫﺠﺔ ﻭﺫﻟﻚ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﻟﻨﻘﻄﺔ ‪.‬‬

‫‪-‬ﺑﺈﻣﻜﺎﻧﻚ ﺇﺧﺘﻴﺎﺭﻳﺎﹰ ﺃﻥ ﺗﻀﻴﻒ ﻗﻮﺳﺎﻥ ﻣﻐﻠﻘﺎﻥ ﺑﻌﺪ ﺇﺳﺘﺪﻋﺎﺀ ﺗﺎﺑﻊ ﻟﻴﺲ ﻟﺔ ﺑﺎﺭﺍﻣﺘﺮﺍﺕ ‪ ،‬ﻭﺑﺈﻣﻜﺎﻧﻚ ﲡﺎﻫﻠﻬﻤﺎ ﻋﻠﻰ ﻛﻞ ﺣﺎﻝ‬

‫ﻣﺜﺎﻝ ‪ :‬ﺍﻟﺘﻌﺮﻳﻔﺎﻥ ﺍﻟﺘﺎﻟﻴﺎﻥ ﻣﺘﻜﺎﻓﺌﺎﻥ ‪:‬‬


‫;)(‪GetCurrentDay‬‬
‫;‪GetCurrentDay‬‬

‫ﺍﻟﺘﺤﻤﻴﻞ ﺍﻟﺰﺍﺋﺪ ﻟﻠﻤﻨﺎﻫﺞ ‪: method overloading‬‬

‫ﺩﻟﻔﻲ ﺗﺪﻋﻢ ﺍﻟﺘﺤﻤﻴﻞ ﺍﻟﺰﺍﺋﺪ ﻟﻠﻤﻨﺎﻫﺞ )ﺍﻟﺘﻮﺍﺑﻊ ‪ +‬ﺍﻹﺟﺮﺍﺋﻴﺎﺕ( ‪ .‬ﻭﻟﻜﻦ ﻣﺎ ﻫﻮ ﺍﻟﺘﺤﻤﻴﻞ ﺍﻟﺰﺍﺋﺪ ﻳﺎﺗﺮﻯ ؟‬

‫ﺍﻟﺘﺤﻤﻴﻞ ﺍﻟﺰﺍﺋﺪ ﻳﻌﲏ ﺃﻥ ﻳﻜﻮﻥ ﻟﺪﻳﻚ ﻣﻨﻬﺠﺎﻥ ﺑﻨﻔﺲ ﺍﻹﺳﻢ ‪ ،‬ﺷﺮﻳﻄﺔ ﺃﻥ ﺗﻘﻮﻡ ﺑﺈﺿﺎﻓﺔ ﺍﻟﻜﻠﻤﺔ ﺍﳌﻔﺘﺎﺣﻴﺔ ‪ overloading‬ﺍﻟﻴﻬﻤﺎ‬
‫ﻭﺃﻥ ﺗﻜﻮﻥ ﻗﺎﺋﻤﺔ ﺍﻟﺒﺎﺭﺍﻣﺘﺮﺍﺕ )ﺍﳌﺘﻐﲑﺍﺕ( ﺍﳋﺎﺻﺔ ﻳﻜﻞ ﻣﻨﻬﻤﺎ ﳐﺘﻠﻔﺔ ﻋﻦ ﺍﻵﺧﺮ ‪) ،‬ﺇﺫﺍ ﺇﺗﻔﻘﺎ ﺑﺎﻹﺳﻢ ﻓﺈﻥ ﺩﻟﻔﻲ ﲝﺎﺟﺔ ﺇﱃ‬
‫ﺷﻲﺀ ﺁﺧﺮ ﻟﻠﺘﻤﻴﻴﺰ ﺑﻴﻨﻬﻤﺎ ﻟﺬﻟﻚ ﻓﺈﻥ ﻣﻨﻬﺠﲔ ﻣﺘﻔﻘﲔ ﺑﺎﻹﺳﻢ ﻭﺍﻟﺒﺎﺭﺍﻣﺘﺮﺍﺕ ﻻ ﳝﻜﻦ ﺃﻥ ﳓﺪﻳﺪ ﺃﻱ ﻣﻨﻬﻤﺎ ﻧﺮﻳﺪ ﺃﻥ ﻧﺴﺘﺨﺪﻡ (‬
‫‪ .‬ﺑﻔﺤﺺ ﺍﻟﺒﺎﺭﺍﻣﺘﺮﺍﺕ ﻳﺴﺘﻄﻴﻊ ﻣﺘﺮﺟﻢ ﺍﻟﻠﻐﺔ )‪ (Compiler‬ﲢﺪﻳﺪ ﺃﻱ ﻭﺍﺣﺪ ﻣﻨﻬﻤﺎ ﻧﺮﻳﺪ ﺃﻥ ﻧﺴﺘﺪﻋﻲ ‪ ،‬ﻭﻳﻘﻮﻡ ﺑﺎﻹﺳﺘﺪﻋﺎﺀ‬
‫ﺍﻟﺼﺤﻴﺢ ﻟﻠﻤﻨﻬﺞ ﺍﻟﺼﺤﻴﺢ ‪ .‬ﺳﻨﺮﻯ ﺗﻄﺒﻴﻘﺎﺕ ﻫﺬﺓ ﺍﳌﻴﺰﺓ ﻻﺣﻘﺎ‬

‫‪٨‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻧﻈﺮﺓ ﺃﻛﺜﺮ ﺗﻔﺼﻴﻼ ﰲ ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ ‪:‬‬

‫‪ -‬ﺍﻟﺘﻐﻠﻴﻒ‬

‫‪ -‬ﺍﻟﻮﺭﺍﺛﺔ‬

‫‪ -‬ﺗﻌﺪﺩﻳﺔ ﺍﻷﺷﻜﺎﻝ‬

‫ﺍﻟﺘﻐﻠﻴﻒ ‪: Encapsulation‬‬

‫ﺗﻌﺘﻤﺪ ﻓﻜﺮﺓ ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ ﻋﻠﻰ ﺇﺧﻔﺎﺀ ﺍﻟﺒﻴﺎﻧﺎﺕ ‪ .‬ﻭﺗﺴﺘﺨﺪﻡ ﺍﻷﺻﻨﺎﻑ ﻟﺘﺤﻘﻴﻖ ﺫﻟﻚ ‪.‬‬

‫ﻳﺘﻢ ﺇﺧﻔﺎﺀ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺩﺍﺧﻞ ﺍﻷﺻﻨﺎﻑ ﺍﳋﺎﺻﺔ ‪‬ﺎ ‪ ،‬ﺃﻭ ﻧﻘﻮﻝ ﻳﺘﻢ ﺗﻐﻠﻴﻒ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺩﺍﺧﻞ ﺍﻷﺻﻨﺎﻑ ‪.‬‬

‫ﻋﺎﺩﺓ ﻳﺘﻢ ﺗﻮﺿﻴﺢ ﻫﺬﺓ ﺍﻟﻔﻜﺮﺓ ﺑﺈﺳﺘﺨﺪﺍﻡ ﻣﺎ ﻳﺴﻤﻰ ﺍﻟﺼﻨﺎﺩﻳﻖ ﺍﻟﺴﻮﺩﺍﺀ )‪ ، (black boxes‬ﺣﻴﺚ ﻻ ﺗﻀﻄﺮ ﺃﻥ ﺗﻌﺮﻑ‬
‫ﻛﻴﻒ ﺗﺘﻢ ﺍﻷﻣﻮﺭ ﺑﺎﻟﺪﺍﺧﻞ ﻭﻣﺎ ﻫﻲ ﺍﶈﺘﻮﻳﺎﺕ ﺍﻟﺪﺍﺧﻠﻴﺔ ‪ ،‬ﻭﻛﻞ ﻣﺎ ﻳﻬﻤﻚ ﻫﻮ ﻛﻴﻒ ﺗﺘﻌﺎﻣﻞ ﻣﻊ ﻭﺍﺟﻬﺔ ﺍﻟﺼﻨﺪﻭﻕ ﺍﻷﺳﻮﺩ‬
‫ﻭﺗﻌﻄﻴﺔ ﻣﻌﻄﻴﺎﺗﻚ ﻭﺗﺄﺧﺬ ﺍﻟﻨﺘﺎﺋﺞ ﺑﻐﺾ ﺍﻟﻨﻈﺮ ﻋﻦ ﻣﺎ ﻳﺘﻢ ﰲ ﺍﻟﺪﺍﺧﻞ ‪ .‬ﺇﻥ ﻣﺎ ﻳﻬﻤﻚ ﻓﻌﻠﻴﺎ ﻣﻦ ﺍﻟﺼﻨﺪﻭﻕ ﻫﻮ ﺁﻟﻴﺔ ﺍﻟﺘﻌﺎﻣﻞ‬
‫ﻣﻌﺔ )ﻣﻊ ﻭﺍﺟﻬﺘﺔ( ﻭﻻ ﺗﻌﻄﻲ ﺇﻫﺘﻤﺎﻣﺎ ﻛﺒﲑﺍ ﻋﻦ ﺗﻔﺎﺻﻴﻞ ﺩﺍﺧﻞ ﺍﻟﺼﻨﺪﻭﻕ ‪ ،‬ﻣﺜﻼ ﻳﻬﻤﻚ ﺃﻥ ﺗﺘﻔﺮﺝ ﻋﻠﻰ ﺍﻟﱪﺍﻣﺞ ﺍﳌﻔﻀﻠﻪ‬
‫ﻋﻠﻰ ﺍﻟﺘﻠﻔﺰﻳﻮﻥ ﻭﺃﻥ ﺗﻌﺮﻑ ﺗﻐﻴﲑ ﺍﶈﻄﺎﺕ ﻭﺇﻃﻔﺎﺀﺓ ﻭﺗﺸﻐﻴﻠﺔ ‪ ،‬ﺑﻐﺾ ﺍﻟﻨﻈﺮ ﻋﻦ ﻓﻬﻢ ﺍﻟﺪﺍﺭﺍﺕ ﺍﻟﺪﺍﺧﻠﻴﺔ ﺍﳌﻜﻮﻧﺔ ﻟﻠﺘﻠﻔﺰﻳﻮﻥ‬
‫‪..‬‬

‫ﺇﺫﻥ ﳔﺰﻥ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺩﺍﺧﻞ ﺍﻷﺻﻨﺎﻑ ﻭﻋﻨﺪﻫﺎ ﳝﻜﻨﻨﺎ ﺃﻥ ﻧﻜﺘﻔﻲ ﲟﻌﺮﻓﺔ ﻛﻴﻔﻴﺔ ﺇﺳﺘﺨﺪﺍﻣﻬﺎ ﻣﻦ ﺍﳋﺎﺭﺝ ‪ .‬ﺇﻥ ﻛﻴﻔﻴﺔ‬
‫ﺍﻹﺳﺘﺨﺪﺍﻡ ﺗﺪﻋﻰ ﻭﺍﺟﻬﺔ ﺍﻟﺼﻨﻒ )‪ (class interface‬ﻭﻫﻲ ﺍﻟﱵ ﺗﺴﻤﺢ ﻟﻸﺟﺰﺍﺀ ﺍﻷﺧﺮﻯ ﻣﻦ ﺍﻟﱪﻧﺎﻣﺞ ﺑﺈﺳﺘﺨﺪﺍﻡ‬
‫ﺍﻷﻏﺮﺍﺽ ﺍﳌﻌﺮﻓﺔ ﻣﻦ ﻫﺬﺍ ﺍﻟﺼﻨﻒ ‪ ،‬ﻭﺑﺎﻟﺘﺎﱄ ﻋﻨﺪﻣﺎ ﺗﺴﺘﺨﺪﻡ ﻏﺮﺽ ﻣﺎ ﻓﺈﻥ ﻣﻌﻈﻢ ﺷﻔﺮﺗﻪ ﺗﻜﻮﻥ ﳐﻔﻴﺔ ‪ ،‬ﻭﻧﺎﺩﺭﺍ ﻣﺎ ﺗﻌﺮﻑ‬
‫ﻣﺎ ﻫﻲ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﻟﺪﺍﺧﻠﻴﻪ ﻟﻪ ﺣﱴ ﺃﻧﻪ ﻗﺪ ﻻ ﺗﻮﺟﺪ ﻃﺮﻳﻘﺔ ﻟﺪﺧﻮﻝ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﳋﺎﺻﺔ ﺑﻪ ﺑﺸﻜﻞ ﻣﺒﺎﺷﺮ ﻣﺎﱂ ﺗﺴﺘﺨﺪﻡ ﺍﳌﻨﺎﻫﺞ‬
‫ﺍﳌﺘﺎﺣﺔ ﻋﻠﻰ ﺍﻟﻮﺍﺟﻬﺔ ﻭﺍﻟﱵ ﺗﺴﻤﺢ ﻟﻚ ﺑﺘﻐﻴﲑ ﻭﻗﺮﺍﺀﺓ ﺍﻟﺒﻴﺎﻧﺎﺕ ‪ ،‬ﻭﺫﻟﻚ ﻳﻌﺘﱪ ﻣﻦ ﺃﻫﻢ ﺍﻟﻔﺮﻭﻕ ﺑﲔ ﺍﻟﱪﳎﺔ ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ‬
‫ﻭ ﺍﻟﱪﳎﺔ ﺍﻟﻜﻼﺳﻴﻜﻴﺔ ﻭﺍﻟﱵ ﺗﻜﻮﻥ ﺍﻟﺒﻴﺎﻧﺎﺕ ﻓﻴﻬﺎ ﻋﺎﻣﺔ ﻟﻜﻞ ﺍﻷﺻﻨﺎﻑ ﻏﲑ ﺗﺎﺑﻌﺔ ﻟﺼﻨﻒ ﳏﺪﺩ ﻛﻤﺎ ﺃﻧﻚ ﺗﺴﺘﻄﻴﻊ ﺗﻐﲑﻫﺎ‬
‫ﻣﺒﺎﺷﺮﺓ ﻭﺑﺎﻟﺘﺎﱄ ﺗﻘﻊ ﰲ ﻣﻄﺐ ﻋﺪﻡ ﺻﻼﺣﻴﺔ ﺍﻟﻘﻴﻤﺔ ﳊﺎﻟﺔ ﺃﻭ ‪‬ﻤﻮﻋﺔ ﺣﺎﻻﺕ ‪...،،‬‬

‫‪٩‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻟﻨﻮﺿﺢ ﻫﺬﺓ ﺍﻟﻨﻘﻄﺔ ﺍﳍﺎﻣﺔ ‪:‬‬

‫ﰲ ﻣﺜﺎﻝ ﺍﻟﺘﺎﺭﻳﺦ ﺍﻟﺴﺎﺑﻖ ‪،‬‬

‫‪ -‬ﻟﻮ ﻛﻨﺎ ﻧﺘﺒﻊ ﺍﻟﻄﺮﻳﻘﺔ ﺍﻟﻜﻼﺳﻴﻜﻴﺔ ﺑﺎﻟﱪﳎﺔ ﻓﺈﻥ ﺍﳌﺘﺤﻮﻻﺕ )ﺍﻟﺒﻴﺎﻧﺎﺕ( ﺳﺘﻜﻮﻥ ﻣﺘﺎﺣﺔ ﻟﻠﺪﺧﻮﻝ ﻭﺍﻟﺘﻐﻴﲑ ﺍﳌﺒﺎﺷﺮ ‪،‬‬
‫ﻭﺑﺎﻟﺘﺎﱄ ﻣﻦ ﺍﳌﻤﻜﻦ ﺇﺩﺧﺎﻝ ﻗﻴﻢ ﻏﲑ ﺻﺎﳊﺔ ﺑﺪﻭﻥ ﻭﺟﻮﺩ ﺇﻣﻜﺎﻧﻴﺔ ﻟﻠﺘﺄﻛﺪ ﻣﻨﻬﺎ ‪ ،‬ﻣﺜﻼ ﻟﻮ ﻗﻤﺖ ﺑﺈﺩﺧﺎﻝ ﺍﻟﺘﺎﺭﻳﺦ‬
‫‪ ٣٠) February 30‬ﺷﺒﺎﻁ( ﻭﺍﻟﺬﻱ ﻫﻮ ﺗﺎﺭﻳﺦ ﺧﺎﻃﻲﺀ ﻹﻥ ﺷﺒﺎﻁ ﻻﳛﻮﻱ ‪ ٣٠‬ﻳﻮﻡ ﻓﺈﻥ ﺍﻟﱪﻧﺎﻣﺞ ﺳﻴﻘﺒﻠﺔ ﻹﻧﻨﺎ ﻋﺮﻓﻨﺎ‬
‫ﻣﺘﺤﻮﻝ ﺍﻟﻴﻮﻡ ﻣﻦ ﺍﻟﻨﻮﻉ ﺍﻟﺼﺤﻴﺢ )‪ (Integer‬ﺍﻟﺬﻱ ﻳﻘﺒﻞ ﻫﺬﺓ ﺍﻟﻘﻴﻤﺔ ‪ ،‬ﻭﺳﺘﺤﺼﻞ ﺍﻷﺧﻄﺎﺀ ﻻﺣﻘﺎ ﻋﻨﺪ ﺍﻟﻌﻤﻠﻴﺎﺕ‬
‫ﺍﳊﺴﺎﺑﻴﺔ ‪ ،‬ﺃﻭ ﺗﻌﻄﻲ ﻧﺘﺎﺋﺞ ﺧﺎﻃﺌﺔ ﲤﺎﻣﺎ ‪.‬‬

‫‪ -‬ﺃﻣﺎ ﰲ ﺣﺎﻝ ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴﺔ ‪ ،‬ﻓﺈﻥ ﺍﻟﺪﺧﻮﻝ ﺍﳌﺒﺎﺷﺮ ﻟﻠﺒﻴﺎﻧﺎﺕ ﻏﲑ ﻣﺴﻤﻮﺡ ﻹﻥ ﺍﻟﺒﻴﺎﻧﺎﺕ ﻣﻐﻠﻔﺔ )ﳐﺒﺄﺓ ( ﰲ ﺍﻟﺼﻨﻒ‬
‫ﻭﺍﻟﻮﺻﻮﻝ ﺇﻟﻴﻬﺎ ﻳﺘﻢ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﳌﻨﺎﻫﺞ ﺍﻟﱵ ﺧﺼﺼﻬﺎ ﺍﻟﺼﻨﻒ ﻟﺬﻟﻚ ‪ ،‬ﺃﻱ ﺃﻧﻚ ﻟﻦ ﺗﺴﺘﺨﺪﻡ ﺍﳌﺘﺤﻮﻝ ﻣﺒﺎﺷﺮﺓ ﺑﻞ‬
‫ﺳﺘﺘﻌﺎﻣﻞ ﻣﻊ ﺇﺟﺮﺍﺋﻴﺔ ﺃﻭ ﺗﺎﺑﻊ ﻹﺩﺧﺎﻝ ﺍﻟﻘﻴﻤﺔ ‪ ،‬ﻭﺑﺎﻟﺘﺎﱄ ﻟﻦ ﻳﻈﻬﺮ ﻣﻌﻨﺎ ﺍﻟﻨﻮﻉ ﺍﻟﺴﺎﺑﻖ ﻣﻦ ﺍﻷﺧﻄﺎﺀ ﻹﻥ ﻫﺬﺓ ﺍﳌﻨﺎﻫﺞ‬
‫ﳝﻜﻦ ﺑﺴﻬﻮﻟﺔ ﺗﻀﻤﻴﻨﻬﺎ ﺷﻔﺮﺍﺕ ﻟﻔﺤﺺ ﺍﻟﻘﻴﻢ ﻭﺍﻟﺘﺄﻛﺪ ﻣﻨﻬﺎ ‪ ،‬ﻭﺭﻓﺾ ﺍﻟﺘﻌﺪﻳﻼﺕ ﰲ ﺣﺎﻝ ﻛﺎﻧﺖ ﺍﻟﻘﻴﻤﺔ ﻏﲑ ﺻﺎﳊﺔ‬
‫‪ .‬ﻻﺣﻆ ﺃﻧﻨﺎ ﺃﺳﺘﺨﺪﻣﻨﺎ ﺍﳌﻨﻬﺞ ‪ SetValue‬ﻟﻀﺒﻂ ﺍﻟﻘﻴﻢ ﻭﱂ ﻧﻘﻢ ﺑﺎﻟﻀﺒﻂ ﺍﳌﺒﺎﺷﺮ ﻭﻫﻨﺎ ﻧﺴﺘﻄﻴﻊ ﺇﺿﺎﻓﺔ ﺍﻟﺸﻔﺮﺓ‬
‫ﺍﳋﺎﺻﺔ ﺑﺎﻟﺘﺤﻘﻖ ﻣﻦ ﺻﻼﺣﻴﺔ ﺍﻟﻘﻴﻤﺔ ‪ ،‬ﻛﺄﻥ ﺗﻜﻮﻥ ﺃﺻﻐﺮ ﻣﻦ ﺣﺪ ﻣﻌﲔ ‪ ،‬ﺃﻭ ﻏﲑ ﺳﺎﻟﺒﺔ ‪ ،‬ﺃﻭ ﺃﻭ ‪...‬‬

‫ﻛﻤﺎ ﺃﻥ ﻟﻠﺘﻐﻠﻴﻒ ﻣﻴﺰﺓ ﺳﺤﺮﻳﺔ ﻟﻠﻤﱪﻣﺞ ﻧﻔﺴﻪ ﻫﺬﺓ ﺍﳌﺮﺓ ‪..‬‬ ‫•‬

‫ﻹ‪‬ﺎ ﺗﺴﻤﺢ ﻟﺔ ﺑﺘﻐﻴﲑ ﺍﻟﺘﺮﻛﻴﺐ ﺍﻟﺪﺍﺧﻠﻲ ﻟﻠﺼﻨﻒ ﰲ ﺍﻟﺘﺤﺪﻳﺜﺎﺕ ﺍﳌﺴﺘﻘﺒﻠﻴﺔ ‪ ،‬ﻭﺑﺎﻟﺘﺎﱄ ﺳﺘﻄﺒﻖ ﺍﻟﺘﻐﻴﲑﺍﺕ ﺗﻠﻘﺎﺋﻴﺎ ﻋﻠﻰ ﺑﻘﻴﺔ‬
‫ﺍﻷﻏﺮﺍﺽ ﺍﻟﱵ ﺇﺳﺘﺨﺪﻣﺖ ﻫﺬﺍ ﺍﻟﺼﻨﻒ ﺑﺈﻗﻞ ﻋﻨﺎﺀ ﳑﻜﻦ ‪ ،‬ﺩﻭﻥ ﺍﳊﺎﺟﺔ ﻟﺘﻐﲑ ﺷﻔﺮﺗﻨﺎ ﰲ ﻣﻨﺎﻃﻖ ﳐﺘﻠﻔﺔ ﻣﻦ ﺍﻟﱪﻧﺎﻣﺞ ‪.‬‬

‫ﻣﻼﺣﻈﺔ ‪:‬‬

‫ﺑﺎﻹﺿﺎﻓﺔ ﺇﱃ ﺍﻟﺘﻐﻠﻴﻒ ﺍﳌﻌﺘﻤﺪ‪-‬ﻋﻠﻰ–ﺍﻟﺼﻨﻒ ﻓﺈﻥ ﺩﻟﻔﻲ ﺗﺪﻋﻢ ﺍﻟﺘﻐﻠﻴﻒ ﺍﳌﻌﺘﻤﺪ‪-‬ﻋﻠﻰ‪-‬ﺍﻟﻮﺣﺪﺓ ‪ ،‬ﲝﻴﺚ ﻛﻞ ﻣﺘﻐﲑ ﺗﻘﻮﻡ‬
‫ﺑﺘﻌﺮﻳﻔﺔ ﰲ ﻗﺴﻢ ﺍﻟـ ‪ Interface‬ﻟﻠﻮﺣﺪﺓ ﺳﻴﺼﺒﺢ ﻣﺮﺋﻴﺎ ﻟﺒﺎﻗﻲ ﻭﺣﺪﺍﺕ ﺍﻟﱪﻧﺎﻣﺞ ﻋﻨﺪ ﺇﺳﺘﺨﺪﺍﻣﻬﺎ ﰲ ﺍﻟﺘﻌﺮﻳﻒ ‪ Uses‬ﰲ‬
‫ﺣﲔ ﺃﻥ ﺍﳌﺘﻐﲑﺍﺕ ﺍﳌﻌﺮﻓﺔ ﰲ ﻗﺴﻢ ﺍﻟـ ‪ Implementation‬ﻫﻲ ﻣﺘﻐﲑﺍﺕ ﳏﻠﻴﺔ ﳍﺬﺓ ﺍﻟﻮﺣﺪﺓ ﻓﻘﻂ ‪.‬‬

‫‪١٠‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﳏﺪﺩﺍﺕ ﺍﻟﻮﺻﻮﻝ ‪: Private, Protected, Public‬‬

‫ﺩﻟﻔﻲ ﲤﻠﻚ ﺛﻼﺙ ﳏﺪﺩﺍﺕ ﻭﺻﻮﻝ ﻣﻦ ﺃﺟﻞ ﺍﻟﺘﻐﻠﻴﻒ ﺍﳌﻌﺘﻤﺪ‪-‬ﻋﻠﻰ‪-‬ﺍﻟﺼﻨﻒ ‪.‬‬

‫ﻭﻫﻲ ‪ ، Private, Protected, Public‬ﺗﺘﺤﻜﻢ ﳏﺪﺩﺍﺕ ﺍﻟﻮﺻﻮﻝ ﲟﺠﺎﻝ ﺍﻟﺮﺅﻳﻪ ﺍﳌﺴﻤﻮﺡ ﺑﻪ ﻣﻦ ﺃﺟﻞ ﺣﻘﻞ ﺃﻭ ﻣﻨﻬﺞ ﻣﺎ‬

‫ﺍﻟﺘﻮﺟﻴﻪ ‪ Private‬ﻳﺪﻝ ﻋﻠﻰ ﺣﻘﻮﻝ ﺍﻟﺼﻨﻒ ﻭﻣﻨﺎﻫﺠﻪ ﺍﻟﱵ ﺗﻜﻮﻥ ﻏﲑ ﻣﺘﺎﺣﺔ ﺧﺎﺭﺝ ﺍﻟﻮﺣﺪﺓ ﺍﻟﱵ ﻋﺮﻑ ﻓﻴﻬﺎ‬ ‫•‬
‫ﺍﻟﺼﻨﻒ ‪ ،‬ﻭﻻ ﳝﻜﻦ ﺍﻟﻮﺻﻮﻝ ﺇﻟﻴﻬﺎ ﺳﻮﻯ ﻣﻦ ﺩﺍﺧﻞ ﻫﺬﻩ ﺍﻟﻮﺣﺪﺓ ‪ ،‬ﻭﺑﺎﻟﺘﺎﱄ ﻫﻲ ﻣﺘﻐﲑﺍﺕ ﳏﻠﻴﻪ ﰲ ﻫﺬﺓ ﺍﻟﻮﺣﺪﺓ‬
‫ﺗﺴﺘﺨﺪﻡ ﻹﲤﺎﻡ ﻋﻤﻞ ﺟﺰﺋﻲ ﻣﺎ ﺩﺍﺧﻞ ﺍﻟﺼﻨﻒ ﻭﻻ ﺩﺍﻋﻲ ﻟﻈﻬﻮﺭﻫﺎ ﻟﺒﻘﻴﺔ ﺍﻟﻌﻨﺎﺻﺮ ‪.‬‬

‫ﺍﻟﺘﻮﺟﻴﻪ ‪ Protected‬ﻳﺴﺘﺨﺪﻡ ﻟﺘﺤﺪﻳﺪ ﳎﺎﻝ ﺭﺅﻳﻪ ﻣﻘﻴ‪‬ﺪ ﳊﻘﻮﻝ ﺍﻟﺼﻨﻒ ﻭﻣﻨﺎﻫﺠﻪ ‪ ،‬ﺣﻴﺚ ﻳﺴﺘﻄﻴﻊ ﺍﻟﺼﻨﻒ‬ ‫•‬

‫ﺍﳊﺎﱄ ﻭﺍﻷﺻﻨﺎﻑ ﺍﳌﻮﺭﺛﺔ ﻣﻨﺔ ﻓﻘﻂ ﺍﻟﻮﺻﻮﻝ ﺇﱃ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﳌﻌﺮﻓﺔ ﺿﻤﻨﻪ ‪ ،‬ﻭﺑﺒﺴﺎﻃﺔ ﻳﺴﺘﻄﻴﻊ ﺍﻟﺼﻨﻒ ﺍﻷﺳﺎﺳﻲ‬
‫ﻭﺍﻷﺻﻨﺎﻑ ﺍﳌﺸﺘﻘﺔ ﻣﻨﻪ ﺑﺎﻹﺿﺎﻓﺔ ﺇﱃ ﺃﻱ ﺷﻔﺮﺓ ﰲ ﻧﻔﺲ ﺍﻟﻮﺣﺪﺓ ﺍﻟﺪﺧﻮﻝ ﺇﱃ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﶈﻤﻴﺔ ﺑـ ‪Protected‬‬
‫ﻭﻓﻘﻂ ﻫﺆﻻﺀ ﻫﻢ ﻣﻦ ﳝﻠﻜﻮﻥ ﲰﺎﺣﻴﺔ ﺍﻟﺪﺧﻮﻝ ‪ .‬ﻫﺬﺍ ﺍﻟﺘﻮﺟﻴﻪ ﻣﺜﻞ ﺳﺎﺑﻘﺔ ﻣﻦ ﻧﺎﺣﻴﺔ ﺃﻧﻪ ﳏﻠﻲ ﺿﻤﻦ ﺍﻟﻮﺣﺪﺓ ‪،‬‬
‫ﻭﻟﻜﻦ ﻧﻀﻴﻒ ﻫﻨﺎ ﺇﻣﻜﺎﻧﻴﺔ ﺍﻟﺮﺅﻳﺔ ﻣﻦ ﻗﺒﻞ ﺍﻷﺻﻨﺎﻑ ﺍﳉﺰﺋﻴﻪ ﺍﳌﺸﺘﻘﺔ ﺍﻟﱵ ﺭﲟﺎ ﲢﺘﺎﺝ ﻫﺬﺓ ﺍﻟﺒﻴﺎﻧﺎﺕ ‪.‬‬

‫ﺍﻟﺘﻮﺟﻴﻪ ‪ Public‬ﻳﺪﻝ ﻋﻠﻰ ﺣﻘﻮﻝ ﻭﻣﻨﺎﻫﺞ ﳝﻜﻦ ﺍﻟﺪﺧﻮﻝ ﺇﻟﻴﻬﺎ ﲝﺮﻳ‪‬ﺔ ﻣﻦ ﺃﻱ ﺟﺰﺀ ﻣﻦ ﺍﻟﱪﻧﺎﻣﺞ ﻛﻤﺎ ﻟﻮ ﺃ‪‬ﺎ‬ ‫•‬
‫ﻣﻌﺮﻓﺔ ﺑﻨﻔﺲ ﺍﻟﻮﺣﺪﺓ ‪ ،‬ﺣﻴﺚ ﻻ ﺗﻮﺟﺪ ﻗﻴﻮﺩ ﰲ ﺍﻟﺪﺧﻮﻝ ﺇﱃ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﳌﻌﺮﻓﺔ ‪‬ﺬﺍ ﺍﻟﺘﻮﺟﻴﺔ ‪.‬‬

‫ﲢﺬﻳﺮ ‪:‬‬

‫ﳏﺪﺩﺍﺕ ﺍﻟﻮﺻﻮﻝ ﺍﻟﺴﺎﺑﻘﺔ ﺗﻘﻮﻡ ﺑﺘﺤﺪﻳﺪ ﺇﻣﻜﺎﻧﻴﺔ ﺩﺧﻮﻝ ﺷﻔﺮﺍﺕ ﻣﻦ ﺧﺎﺭﺝ ﺍﻟﻮﺣﺪﺓ ﺇﱃ ﺍﻟﺼﻨﻒ ﺍﳌﻌﺮﻑ ﻓﻴﻬﺎ ‪ ،‬ﻭﺑﺎﻟﺘﺎﱄ‬
‫ﺇﺫﺍ ﻭﺟﺪ ﺻﻨﻔﺎﻥ ﰲ ﻧﻔﺲ ﺍﻟﻮﺣﺪﺓ ﻓﻼ ﺗﻮﺟﺪ ﲪﺎﻳﺔ ﻟﺪﺧﻮﻝ ﺇﺣﺪﳘﺎ ﺇﱃ ﺣﻘﻮﻝ ﺍﳌﻌﺮﻓﺔ ‪ Private‬ﻣﻦ ﺍﻟﺼﻨﻒ ﺍﻵﺧﺮ ‪..‬‬

‫ﺍﻟﺘﻐﻠﻴﻒ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﳋﺼﺎﺋﺺ ‪: Properties‬‬

‫ﺍﳋﺼﺎﺋﺺ ﺗﻌﺘﲑ ﻣﻦ ﺃﺭﻭﻉ ﺗﻘﻨﻴﺎﺕ ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴﺔ ‪ ،‬ﻭﲤﺜﻞ ﻓﻜﺮﺓ ﺍﻟﺘﻐﻠﻴﻒ ﺑﺸﻜﻠﻬﺎ ﺍﻷﻣﺜﻞ ‪.‬‬

‫ﻭﺍﳋﺼﺎﺋﺺ ﺑﺸﻜﻞ ﻋﺎﻡ ﻫﻲ ﺃﻭﻝ ﻣﺎ ﺗﻌﻠﻤﻨﺎ ﺍﻟﺘﻌﺎﻣﻞ ﻣﻌﻪ ﰲ ﻣﺮﺣﻠﺔ ﺍﳌﺒﺘﺪﺀ ‪ ،‬ﻭﻟﻠﺘﺒﺴﻴﻂ ﻓﺈﻥ ﻛﻞ ﻣﺎ ﺗﺮﺍﻩ ﰲ ﺿﺎﺑﻂ‬
‫ﺍﻟﻜﺎﺋﻨﺎﺕ ﻋﺒﺎﺭﺓ ﻋﻦ ﺧﺼﺎﺋﺺ ‪ ،‬ﻭﺍﻟﻔﻜﺮﺓ ﻫﻲ ﺃﻧﻚ ﺗﺘﻌﺎﻣﻞ ﻣﻊ ﺇﺳﻢ ‪ ،‬ﻭﺍﻟﺬﻱ ﳜﻔﻲ ﻋﻨﻚ ﺑﺸﻜﻞ ﻛﺎﻣﻞ ﺗﻔﺎﺻﻴﻞ ﺍﻟﺘﻨﻔﻴﺬ‬
‫‪ ،‬ﻭﺗﺼﺒﺢ ﻣﻬﻤﺘﻚ ﺍﳊﺎﻟﻴﺔ ﻛﻤﺴﺘﺨﺪﻡ ﻟﻠﺼﻨﻒ ﻫﻲ ﻗﺮﺍﺀﺓ ﺍﻟﻘﻴﻢ ﻣﻨﺔ ﺃﻭﻛﺘﺎﺑﺘﻬﺎ ﺇﻟﻴﺔ ‪ ،‬ﺃﻋﺠﺒﲏ ﺗﻌﺮﻳﻒ ﺃﺣﺪ ﺍﻟﻜﺘﺎﺏ ﻋﻨﺪﻣﺎ‬
‫ﻗﺎﻝ ﺃﻥ ﺍﳋﺼﺎﺋﺺ ﻫﻲ ﺣﻘﻮﻝ ﺇﻓﺘﺮﺍﺿﻴﻪ )‪. (virtual fields‬‬

‫‪١١‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺭﲟﺎ ﻻﺣﻈﺖ ﰲ ﺍﻟﻔﻘﺮﺓ ﺍﻟﺴﺎﺑﻘﺔ ﺃﻧﻨﺎ ﳚﺐ ﺃﻥ ﻧﺪﺧﻞ ﻟﻠﺒﻴﺎﻧﺎﺕ ﰲ ﺣﺎﻟﺔ ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴﺔ ﻋﻦ ﻃﺮﻳﻖ ﺍﳌﻨﺎﻫﺞ ﺑﺪﻻ ﻣﻦ‬
‫ﺍﻟﺪﺧﻮﻝ ﺍﳌﺒﺎﺷﺮ ‪ ،‬ﻭﻫﺬﺍ ﻳﺒﺪﻭ ﺷﻴﺌﺎ ﻣﺮﺑﻜﺎ ﻗﻠﻴﻼ ‪ ،‬ﺧﺎﺻﺔ ﺃﻥ ﻣﻨﻬﺞ ﺍﻟﻘﺮﺍﺀﺓ ﺳﻴﻜﻮﻥ ﳐﺘﻠﻒ ﻋﻦ ﻣﻨﻬﺞ ﺍﻟﻜﺘﺎﺑﺔ ‪،‬‬

‫ﺇﺫﺍ ﺑﻨﻴﻨﺎ ﺣﻘﻮﻝ ﺇﻓﺘﺮﺍﺿﻴﺔ ﺗﺴﺘﺨﺪﻡ ﻫﺬﺓ ﺍﳌﻨﺎﻫﺞ ﻭﲣﻔﻴﻬﺎ ﻋﻨﺎ ﻓﺈﻧﻨﺎ ﺳﻨﻜﺴﺐ ﺳﻬﻮﻟﺔ ﺍﻟﺪﺧﻮﻝ ﺍﳌﺒﺎﺷﺮ ﻟﻠﺒﻴﺎﻧﺎﺕ ﻭﻗﻮﺓ‬
‫ﺍﻟﺘﻐﻠﻴﻒ ‪ .‬ﻫﺬﺓ ﺍﳊﻘﻮﻝ ﺍﻹﻓﺘﺮﺍﺿﻴﺔ ﻫﻲ ﺍﳋﺼﺎﺋﺺ ‪ ،‬ﻭﻧﺘﻌﺎﻣﻞ ﻣﻌﻬﺎ ﻣﺜﻠﻤﺎ ﻧﺘﻌﺎﻣﻞ ﻣﻊ ﺍﳊﻘﻮﻝ ﺍﻟﻌﺎﺩﻳﺔ ‪.‬‬

‫ﺗﺄﻣﻞ ﺍﻟﺸﻔﺮﺓ ﺍﻟﺒﺴﻴﻄﺔ ﺍﻟﺘﺎﻟﻴﺔ ‪:‬‬


‫;‪Edit1.Text := Button1.Caption‬‬

‫‪ Caption‬ﻣﻦ ﺍﻟﻐﺮﺽ ‪Button1‬‬ ‫ﻻﺣﻆ ﺃﻧﺎﻥ ﺇﺳﺘﺨﺪﻣﻨﺎ ﺍﳋﺎﺻﻴﺔ ‪ Text‬ﺍﳌﺘﻌﻠﻘﺔ ﺑﺎﻟﻐﺮﺽ ‪ Edit1‬ﻟﻠﻜﺘﺎﺑﺔ ﻓﻴﻬﺎ ‪ ،‬ﻭﺍﳋﺎﺻﻴﺔ‬
‫ﻟﻠﻘﺮﺍﺀﺓ ﻣﻨﻬﺎ ‪ .‬ﻭﺑﺒﺴﺎﻃﺔ ﺃﺻﺒﺤﻨﺎ ‪‬ﺬﺓ ﺍﻟﻔﻜﺮﺓ ﺍﻟﺮﺍﺋﻌﺔ ﻧﻀﻴﻊ ﺍﻟﻮﻗﺖ ﺑﺎﻟﺘﻔﻜﲑ ﺑﺪﻻ ﻣﻦ ﺇﺿﺎﻋﺔ ﺍﻟﻮﻗﺖ ﺑﻜﺘﺎﺑﺔ ﺍﻟﺸﻔﺮﺓ ‪،‬‬
‫ﺑﺎﻟﺘﺄﻛﻴﺪ ﺗﻮﺟﺪ ﻣﻨﺎﻫﺞ ﺧﺎﺻﺔ ﻟﻠﻜﺘﺎﺑﺔ ﺇﱃ ﺍﳋﺎﺻﻴﺔ ‪ Text‬ﻭﻟﻠﻘﺮﺍﺀﺓ ﻣﻨﻬﺎ ‪ ،‬ﻟﻜﻦ ﺍﳋﺎﺻﻴﺔ ‪ Text‬ﺃﺧﻔﺖ ﻫﺬﺓ ﺍﻹﺭﺑﺎﻛﺎﺕ‬
‫ﻋﻨ‪‬ﺎ ﻭﲰﺤﺖ ﻟﻨﺎ ﺑﺈﺳﺘﺨﺪﺍﻣﻬﺎ ﺑﻐﺾ ﺍﻟﻨﻈﺮ ﻋﻦ ﻣﻌﺮﻓﺘﻨﺎ ﺑﺸﻔﺮ‪‬ﺎ ﺍﳌﺨﻔﻴﺔ ﳏﻘﻘﺔ ﺑﺬﻟﻚ ﺗﻐﻠﻴﻔﺎ ﻣﺜﺎﻟﻴﺎﹰ ‪.‬‬

‫ﺗﻌﺮﻳﻒ ﺧﺎﺻﻴﺔ ﺟﺪﻳﺪﺓ ‪:‬‬

‫ﺍﻟﻔﻘﺮﻩ ﺍﻟﺴﺒﻘﺔ ﺗﻜﻠﻤﺖ ﻋﻦ ﻣﺴﺘﺨﺪﻡ ﺍﻟﺼﻨﻒ ﺍﻟﺬﻱ ﻳﺴﺘﻄﻴﻊ ﺇﺳﺘﺨﺪﺍﻡ ﺍﳋﻮﺍﺹ ﺑﺴﻬﻮﻟﺔ ‪ ،‬ﻫﺬﺓ ﺍﻟﻔﻘﺮﺓ ﺳﺘﺘﻜﻠﻢ ﻋﻦ ﺑﺎﱐ‬
‫ﺍﻟﺼﻨﻒ ﺍﻟﺬﻱ ﻳﺆﻣﻦ ﻫﺬﺓ ﺍﻟﺴﻬﻮﻟﺔ ‪.‬‬

‫ﻋﺮﻓﻨﺎ ﺍﻵﻥ ﺃﻥ ﻟﻠﺨﺎﺻﻴﺔ ﺇﺯﺩﻭﺍﺟﻴﺔ ﺑﺎﻟﺘﻌﺎﻣﻞ ‪ ..‬ﻣﺮﺓ ﻗﺮﺍﺀﺓ ‪ ،‬ﻭﻣﺮﺓ ﻛﺘﺎﺑﺔ‬

‫ﻭﺑﻨﺎﺀ ﻋﻠﻰ ﺫﻟﻚ ﻟﺘﻌﺮﻳﻒ ﺧﺎﺻﻴﺔ ﻣﺎ ﳓﻦ ﳓﺘﺎﺝ ﻟﺘﻌﺮﻳﻒ ﻗﺎﺑﻠﻴﺔ ﺍﻟﻘﺮﺍﺀﺓ ﻭﻗﺎﺑﻠﻴﺔ ﺍﻟﻜﺘﺎﺑﺔ ﺃﻳﻀﺎ ‪ ،‬ﻭﻳﺘﻢ ﺫﻟﻚ ﺑﺒﺴﺎﻃﺔ ﻋﻦ‬
‫ﻃﺮﻳﻖ ﺍﻟﻜﻠﻤﺘﲔ ﺍﳌﻔﺘﺎﺣﻴﺘﲔ ‪ Read , Write‬ﻛﻤﺎ ﺃﻧﻨﺎ ﻧﺴﺘﺨﺪﻡ ﺍﻟﻜﻠﻤﺔ ﺍﶈﺠﻮﺯﺓ ‪ property‬ﻟﺘﻌﺮﻳﻒ ﺧﺎﺻﻴﺔ ﺟﺪﻳﺪﺓ‬

‫ﺃﻣﺜﻠﺔ‪:‬‬
‫;‪1- property Month: Integer read FMonth write FMonth‬‬

‫;‪2- property Month: Integer read FMonth write SetMonth‬‬

‫;‪3- property Month: Integer read GetMonth write SetMonth‬‬

‫ﺣﻴﺚ ‪ Fmonth‬ﻣﺘﻐﲑ ﻣﻌﺮﻑ ﻛـ ‪ ، Private‬ﻭ ‪ SetMonth‬ﺇﺟﺮﺍﺋﻴﺔ ﻭ ‪ GetMonth‬ﺗﺎﺑﻊ ﻣﻌﺮﻓﺎﻥ ﺿﻤﻦ ﺍﻟﺼﻨﻒ ‪.‬‬

‫‪١٢‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﳊﺎﻟﺔ ﺍﻷﻭﱃ ‪ :‬ﻭﻫﻲ ﺃﺑﺴﻂ ﺍﳊﺎﻻﺕ ‪ ،‬ﺃﻥ ﻧﻘﻮﻡ ﺑﺘﻌﺮﻳﻒ ﻣﺘﺤﻮﻝ ﻣﺎ ‪ Fmonth‬ﻣﺜﻼ ﻣﻦ ﺃﺟﻞ ﺍﻟﻘﺮﺍﺀﺓ ﻭﺍﻟﻜﺘﺎﺑﺔ ‪ ،‬ﺑﺪﻭﻥ‬
‫ﺇﺳﺘﺨﺪﺍﻡ ﺃﻱ ﻣﻨﻬﺞ ‪ ،‬ﺍﻟﻘﺮﺍﺀﺓ ﺗﺘﻢ ﻣﻨﻪ ﻭﺍﻟﻜﺘﺎﺑﺔ ﺇﻟﻴﺔ ‪ ،‬ﻭﻃﺒﻌﺎ ﻻ ﳝﻜﻦ ﻫﻨﺎ ﺍﻟﺘﺄﻛﺪ ﻣﻦ ﺻﺤﺔ ﺍﻹﺩﺧﺎﻝ ‪ ،‬ﺃﻭ ﺇﺭﻓﺎﻕ ﺇﺩﺧﺎﻝ‬
‫ﺃﻭ ﺇﺧﺮﺍﺝ ﺍﻟﻘﻴﻤﺔ ﲝﺪﺙ ﻣﺎ ‪.‬‬

‫ﺍﳊﺎﻟﺔ ﺍﻟﺜﺎﻧﻴﺔ ‪:‬ﻗﻤﻨﺎ ﺑﺎﻟﻘﺮﺍﺀﺓ ﻣﻦ ﻣﺘﺤﻮﻝ )‪ (Fmonth‬ﺑﺸﻜﻞ ﻃﺒﻴﻌﻲ ﻣﺜﻞ ﺍﳊﺎﻟﺔ ﺍﻷﻭﱃ ‪ ،‬ﺣﻴﺚ ﺃﻧﺔ ﰲ ﻛﺜﲑ ﻣﻦ ﺍﻷﺣﻴﺎﻥ‬
‫ﻻ ﳓﺘﺎﺝ ﺍﻟﺘﺄﻛﺪ ﻣﻦ ﺻﺤﺔ ﺍﻹﺧﺮﺍﺝ ﻃﺎﳌﺎ ﻛﻨﺎ ﻗﺪ ﺗﺄﻛﺪﻧﺎ ﻣﻦ ﺻﺤﺔ ﺍﻹﺩﺧﺎﻝ ﻣﻨﺬ ﺍﻟﺒﺪﺍﻳﺔ ‪.‬‬

‫ﺃﻣﺎ ﺍﻟﻜﺘﺎﺑﺔ ﻓﺘﺘﻢ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﻹﺟﺮﺍﺋﻴﺔ ‪ ، SetMonth‬ﻭﻫﻨﺎ ﻧﺴﺘﻄﻴﻊ ﺍﻟﺘﺄﻛﺪ ﻣﻦ ﺻﻼﺣﻴﺔ ﺍﻷﺩﺧﺎﻝ ﺃﻭ ﺇﺭﻓﺎﻕ ﺍﻹﺩﺧﺎﻝ‬
‫ﺑﺄﺣﺪﺍﺙ ﻣﺎ )ﺇﻟﻐﺎﺀ ﺗﻌﻄﻴﻞ ﺧﻮﺍﺹ ﻣﻌﻴﻨﺔ ﺑﻌﺪ ﺍﻹﺩﺧﺎﻝ ﻣﺜﻼ( ‪ ،‬ﻭﺑﺎﻟﻄﺒﻊ ﻫﺬﺓ ﺍﳊﺎﻟﺔ ﻣﺴﺘﺨﺪﻣﺔ ﻛﺜﲑﺍ ﻋﻠﻰ ﻋﻜﺲ ﺍﳊﺎﻟﺔ‬
‫ﺍﻷﻭﱃ ‪.‬‬

‫ﺍﳊﺎﻟﺔ ﺍﻟﺜﺎﻟﺜﺔ ‪ :‬ﺇﺳﺘﺨﺪﻣﻨﺎ ﺍﻟﺘﺎﺑﻊ ‪ GetMonth‬ﻟﻺﺩﺧﺎﻝ ﻭﺍﻹﺟﺮﺍﺋﻴﺔ ‪ SetMonth‬ﻟﻺﺧﺮﺍﺝ ‪ ،‬ﻭﻫﻲ ﺍﳊﺎﻟﺔ ﺍﻟﻌﺎﻣﺔ ‪.‬‬

‫ﻣﻼﺣﻈﺔ ‪ :‬ﻗﺮﺍﺀﺓ ﺍﳋﺎﺻﻴﺔ ﺳﺘﻌﻴﺪ ﻗﻴﻤﺔ ﻭﺍﺣﺪﺓ ﻣﻨﻬﺎ ‪ ،‬ﻭﺑﺎﻟﺘﺎﱄ ﻣﻦ ﺍﳌﺜﺎﱄ ﻫﻨﺎ ﺇﺳﺘﺨﺪﻡ ﺗﺎﺑﻊ )‪ (Function‬ﻟﻠﻘﺮﺍﺀﺓ ‪.‬‬

‫ﺍﻟﻜﺘﺎﺑﺔ ﻟﻦ ﺗﻌﻴﺪ ﻗﻴﻢ ﻭﻟﻜﻨﻬﺎ ﺳﺘﺪﺧﻞ ﻗﻴﻤﺔ ﺿﻤﻦ ﺑﺎﺭﺍﻣﺘﺮﺍﺕ ﺍﳌﻨﻬﺞ ‪ ،‬ﻟﺬﻟﻚ ﻧﺴﺘﺨﺪﻡ ﺇﺟﺮﺍﺋﻴﺔ )‪ (Procedure‬ﻟﻠﻜﺘﺎﺑﺔ ‪.‬‬

‫ﻋﺎﺩﺓ ﺗﻜﻮﻥ ﺣﻘﻮﻝ ﺍﻟﺒﻴﺎﻧﺎﺕ ﻭﻣﻨﺎﻫﺞ ﺍﻟﺪﺧﻮﻝ ﺍﻟﺴﺎﺑﻘﺔ ‪) Private‬ﻭﻣﻦ ﺍﳌﻤﻜﻦ ﺃﻥ ﺗﻜﻮﻥ ‪(Protected‬‬

‫ﺑﻴﻨﻤﺎ ﺗﻜﻮﻥ ﺍﳋﺼﺎﺋﺺ ‪. Public‬‬

‫ﻭﻫﺬﺍ ﻳﻌﻄﻲ ﺩﺭﺟﺔ ﻣﺜﺎﻟﻴﺔ ﻣﻦ ﺍﻟﺘﻐﻠﻴﻒ‪ ،‬ﻹﻧﻚ ﺗﺴﺘﻄﻴﻊ ﺗﻐﻴﲑ ﺑﻴﺎﻧﺎﺕ ﺍﻟﺼﻨﻒ ﺃﻭ ﻣﻨﺎﻫﺞ ﺍﻟﻘﺮﺍﺀﺓ ﻭﺍﻟﻜﺘﺎﺑﺔ )ﻭﺍﻟﱵ ﻫﻲ ﻏﲑ‬
‫ﻣﺮﺋﻴﺔ ﳌﺴﺘﺨﺪﻡ ﺍﻟﺼﻨﻒ ( ﺩﻭﻥ ﺃﻥ ﻳﺘﺄﺛﺮ ‪‬ﺎ ﻣﺴﺘﺨﺪﻡ ﺍﻟﺼﻨﻒ ﻭﻟﻦ ﻳﻀﻄﺮ ﻟﺘﻐﻴﲑ ﺷﻔﺮﺗﺔ ﻹﻧﺔ ﻳﺴﺘﺨﺪﻡ ﺃﲰﺎﺀ ﺍﳋﻮﺍﺹ‬
‫ﻓﻘﻂ ﻭ ﺍﻟﱵ ﺑﻘﻴﺖ ﺛﺎﺑﺘﺔ ‪ ،‬ﰲ ﺣﲔ ﺃﻥ ﻛﻞ ﺍﻟﺘﻐﲑﺍﺕ ﰲ ﻃﺮﻳﻘﺔ ﺍﻟﻘﺮﺍﺀﺓ ﻭﺍﻟﻜﺘﺎﺑﺔ ﻟﻦ ﺗﺆﺛﺮ ﻋﻠﻴﺔ ‪..‬‬

‫ﺗﺬﻛﺮ ﺍﻟﺼﻨﺪﻭﻕ ﺍﻷﺳﻮﺩ ‪ ،‬ﺍﳌﺴﺘﺨﺪﻡ ﳝﻠﻚ ﺇﺳﻢ ﺍﳋﺎﺻﻴﺔ ﻭﻳﺘﻌﺎﻣﻞ ﻣﻌﻬﺎ ‪ ،‬ﻃﺎﳌﺎ ﺑﻘﻲ ﺇﺳﻢ ﺍﳋﺎﺻﻴﺔ ﺛﺎﺑﺘﺎ ﻓﺈﻥ ﻋﻤﻠﺔ ﻟﻦ‬
‫ﻳﺘﺄﺛﺮ ﺑﺄﻱ ﺗﻐﻴﲑ ‪.‬‬

‫‪١٣‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻣﺜﺎﻝ ﻋﻤﻠﻲ‬

‫‪----------‬‬

‫ﺍﳍﺪﻑ ‪ :‬ﺍﻟﺘﺪﺭﻳﺐ ﻋﻠﻰ ﺑﻨﺎﺀ ﺃﺻﻨﺎﻑ ﺟﺪﻳﺪﺓ ‪ ،‬ﻭﺗﻄﺒﻴﻖ ﻣﺎ ﺗﻌﻠﻤﻨﺎﺓ ﰲ ﺍﻟﻔﻘﺮﺍﺕ ﺍﻟﺴﺎﺑﻘﺔ ﻣﻦ ﺇﻧﺸﺎﺀ ﺍﳌﻨﺎﻫﺞ ﻭﺍﳋﺼﺎﺋﺺ‬
‫ﻭﺍﻟﺘﻌﺎﻣﻞ ﻣﻊ ﳏﺪﺩﺍﺕ ﺍﻟﻮﺻﻮﻝ ‪.‬‬

‫ﺇﺫﻥ ﻫﺪﻓﻨﺎ ﻫﻮ ﺑﻨﺎﺀ ﺻﻨﻒ ﺟﺪﻳﺪ ﻟﻠﺘﺎﺭﻳﺦ ‪،‬‬

‫ﻣﺎﺫﺍ ﻧﺮﻳﺪ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ ،،‬ﺍﻟﻘﺮﺍﺀﺓ ﻣﻨﺔ ﻭﺍﻟﻜﺘﺎﺑﺔ ﺇﻟﻴﺔ ‪ ،‬ﺑﺎﻹﺿﺎﻓﺔ ﺇﱃ ﺇﺟﺮﺍﺀ ﺑﻌﺾ ﺍﻟﺘﺤﻜﻤﺎﺕ ﻭﺍﻟﻌﻤﻠﻴﺎﺕ ﺍﳌﻔﻴﺪﺓ ‪ .‬ﻭﻟﻜﻲ‬
‫ﳝﻠﻚ ﺍﳌﺜﺎﻝ ﺻﻔﺔ ﻣﺴﺄﻟﺔ ﲝﻴﺚ ﳝﻜﻨﻚ ﲡﺮﻳﺐ ﺣﻠﻬﺎ ﻟﻮﺣﺪﻙ ‪ ،‬ﺳﺄﻗﻮﻡ ﺑﺘﻔﺼﻴﻞ ﺫﻟﻚ ‪:‬‬

‫ﻣﻊ ﻣﺮﺍﻋﺎﺓ ﺍﳋﻮﺍﺹ ﺍﻟﺘﺎﻟﻴﺔ‪:‬‬ ‫ﺑﺎﻹﺳﻢ ‪Tdate‬‬ ‫ﺍﳌﻄﻠﻮﺏ ‪ :‬ﺑﻨﺎﺀ ﺻﻨﻒ ﺟﺪﻳﺪ‬

‫‪ -‬ﺇﻣﻜﺎﻧﻴﺔ ﺿﺒﻂ ﺍﻟﻘﻴﻤﺔ ﺑﻄﺮﻳﻘﺘﲔ ‪ .‬ﺃﻭﻻ ‪:‬ﻋﻦ ﻃﺮﻳﻖ ﺇﺩﺧﺎﻝ ﺛﻼﺙ ﻗﻴﻢ ﻟﻠﻴﻮﻡ ﻭﺍﻟﺸﻬﺮ ﻭﺍﻟﺴﻨﺔ ‪ ،‬ﺛﺎﻧﻴﺎ‪ :‬ﻋﻦ ﻃﺮﻳﻖ ﺇﺩﺧﺎﻝ‬
‫ﻗﻴﻤﺔ ﻭﺍﺣﺪﺓ ﻣﻦ ﺍﻟﻨﻤﻂ ‪TdateTime‬‬

‫‪ -‬ﺇﻣﻜﺎﻧﻴﺔ ﻣﻌﺮﻓﺔ ﺇﺫﺍ ﻛﺎﻧﺖ ﺍﻟﺴﻨﺔ ﺍﳊﺎﻟﻴﺔ ﻛﺒﻴﺴﺔ ﺃﻭ ﻻ ؟‬

‫‪ -‬ﺇﻣﻜﺎﻧﻴﺔ ﺇﺧﺮﺍﺝ ﺍﻟﺘﺎﺭﻳﺦ ﺑﺸﻜﻞ ﻧﺼﻲ ‪. String‬‬

‫‪ -‬ﻭﺟﻮﺩ ﻣﻨﻬﺞ ﺯﻳﺎﺩﺓ ﻳﻮﻡ ‪ ،‬ﲝﻴﺚ ﻳﺰﻳﺪ ﻳﻮﻡ ﻟﻠﺘﺎﺭﻳﺦ ﺍﳌﺨﺰﻥ ﻛﻠﻤﺎ ﰎ ﺗﻨﻔﻴﺬﺓ ‪.‬‬

‫‪ -‬ﻭﺟﻮﺩ ﺛﻼﺙ ﺧﺼﺎﺋﺺ ‪ Year , Month , Day‬ﳝﻜﻦ ﺍﻟﺘﻌﺎﻣﻞ ﻣﻌﻬﺎ )ﻗﺮﺍﺀﺓ ﻭﻛﺘﺎﺑﺔ ﺇﱃ ﻛﻞ ﻣﻨﻬﺎ ( ‪.‬‬

‫ﻛﻴﻒ ﻧﻘﻮﻡ ﺑﺬﻟﻚ ؟‬

‫ﺗﺬﻛﺮ ﺃﻧﺔ ﻻﻳﻮﺟﺪ ﺷﻲﺀ ﰲ ﺍﻟﱪﳎﺔ ﻳﺘﻢ ﻋﻤﻠﺔ ﺩﻓﻌﺔ ﻭﺍﺣﺪﺓ ‪ ،‬ﻟﺬﻟﻚ ﺳﻨﻘﻮﻡ ﺑﺒﻨﺎﺀ ﺍﻟﺼﻨﻒ ﺧﻄﻮﺓ ﺧﻄﻮﺓ ﻭﺗﻌﺪﻳﻞ ﺷﻔﺮﺗﻨﺎ‬
‫ﻛﻞ ﻣﺮﺓ ﻛﺄﻧﻨﺎ ﻧﻌﻤﻞ ﻋﻠﻰ ﺣﻮﺍﺳﻴﺒﻨﺎ ﺍﻟﺸﺨﺼﻴﺔ ﻣﻨﺬ ﺍﻟﺒﺪﺍﻳﺔ ‪.‬‬

‫ﻃﺮﻳﻘﱵ ﺑﺎﻟﻌﻤﻞ ﻫﻲ ﺍﻟﻄﺮﻳﻘﺔ ﺍﻟﺘﺮﺍﺟﻌﻴﺔ ﲝﻴﺚ ﻧﻨﻄﻠﻖ ﻣﻦ ﺍﻵﺧﺮ ﺣﱴ ﻧﺼﻞ ﺇﱃ ﺍﻟﺒﺪﺍﻳﺔ ‪ ،‬ﻣﺜﻼ ﺩﻋﻨﺎ ﻧﻔﻜﺮ ﻛﻴﻒ ﺳﻴﺼﺒﺢ‬
‫ﺍﻟﺼﻨﻒ ﺍﳉﺪﻳﺪ ﻭﻣﺎ ﻫﻲ ﺧﺼﺎﺋﺼﺔ ﻭﻣﻨﺎﻫﺠﻪ ﻗﺒﻞ ﺍﻟﺒﺪﺀ ﺑﺎﻟﻌﻤﻞ ‪.‬‬

‫‪١٤‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫‪ ،‬ﻭﻗﺪ ﺗﻌﻠﻤﻨﺎ ﺫﻟﻚ ﺳﺎﺑﻘﺎ ﻭﻫﻮ ﺳﻬﻞ ‪:‬‬ ‫ﺑﺎﻹﺳﻢ ‪Tdate‬‬ ‫ﺃﻭﻻ ﻋﻠﻲ ﺃﻥ ﺃﻗﻮﻡ ﺑﺒﻨﺎﺀ ﺻﻨﻒ ﺟﺪﻳﺪ‬
‫‪type‬‬

‫‪TDate = class‬‬

‫‪ -‬ﻣﻨﻬﺞ "ﺿﺒﻂ ﺍﻟﻘﻴﻤﺔ" ﻟﻦ ﻳﺮﺟﻊ ﺃﻱ ﻗﻴﻢ ﺑﻞ ﺳﻨﻤﺮﺭ ﻟﺔ ﺍﻟﻘﻴﻢ ﻋﻠﻰ ﺷﻜﻞ ﺑﺎﺭﺍﻣﺘﺮﺍﺕ ‪ ،‬ﻟﺬﻟﻚ ﻣﻦ ﺍﻷﻧﺴﺐ ﺃﻥ ﻳﻜﻮﻥ‬
‫ﺇﺟﺮﺍﺋﻴﺔ ‪ Procedure‬ﻭﻟﻴﺲ ﺗﺎﺑﻌﺎ ‪، Function‬‬

‫ﻧﺮﻳﺪ‬

‫ﻧﺮﻳﺪ ﺇﺟﺮﺍﺋﻴﺘﲔ ﳐﺘﻠﻔﺘﲔ ﻟﻀﺒﻂ ﺍﻟﻘﻴﻤﺔ ‪ ،‬ﻭﻟﻜﻦ ﺗﺬﻛﺮ ﺃﻧﺔ ﺑﺈﻣﻜﺎﻧﻨﺎ ﺇﺳﺘﺨﺪﺍﻡ ﻧﻔﺲ ﺍﻹﺳﻢ ﻟﻜﻼ ﺍﻹﺟﺮﺍﺋﻴﺘﲔ ﻭﺫﻟﻚ‬
‫ﺑﺎﻹﺳﺘﻔﺎﺩﺓ ﻣﻦ ﺧﺎﺻﻴﺔ ﺍﻟﺘﺤﻤﻴﻞ ﺍﻟﺰﺍﺋﺪ ﰲ ﺩﻟﻔﻲ )ﺣﻴﺚ ﺳﻴﻜﻮﻥ ﺍﻟﻔﺮﻕ ﺑﺎﻟﱪﺍﻣﺘﺮﺍﺕ( ‪ ،‬ﻭﺳﺄﺧﺘﺎﺭ ﺇﲰﺎ ﻣﻨﺎﺳﺒﺎ ﳍﻤﺎ ﻭﻟﻴﻜﻦ‬
‫"‪. " SetValue‬‬

‫ﻓﺈﺫﺍ ﺳﻴﺒﺪﻭ ﺇﺳﺘﺪﻋﺎﺀ ﻛﻞ ﻣﻦ ﺍﻹﺟﺮﺍﺋﻴﺘﲔ ﺑﻌﺪ ﺍﻹﻧﺘﻬﺎﺀ ﺑﺎﻟﺸﻜﻞ ‪:‬‬

‫ﺍﻷﻭﱃ ‪TheDate.SetValue (2004, 7, 1); //‬‬ ‫ﺍﻹﺟﺮﺍﺋﻴﺔ‬

‫;)‪TheDate.SetValue(now‬‬ ‫ﺍﻟﺜﺎﻧﻴﺔ ‪//‬‬ ‫ﺍﻹﺟﺮﺍﺋﻴﺔ‬

‫)‪ Now‬ﻳﻌﻴﺪ ﻗﻴﻤﺔ ﺍﻟﺘﺎﺭﻳﺦ ﺍﳊﺎﱄ ﻣﻦ ﺍﻟﻨﻮﻉ ‪(TdateTime‬‬

‫‪ -‬ﻧﺮﻳﺪ ﺃﻳﻀﺎ ﻣﻨﻬﺞ ﻟﻴﻌﺮﻑ ﺇﺫﺍ ﻛﺎﻧﺖ ﺍﻟﺴﻨﺔ ﻛﺒﻴﺴﺔ ﺃﻭ ﻻ ‪ ،‬ﻣﻦ ﺍﳌﻼﺣﻆ ﺃﻧﺔ ﺳﻴﻌﻴﺪ ﻗﻴﻤﻴﺔ ﺑﻮﻟﻴﺎﻧﻴﺔ ﻭﺍﺣﺪﺓ ‪ ،‬ﻟﺬﻟﻚ ﻣﻦ‬
‫ﺍﳌﻨﺎﺳﺐ ﺃﻥ ﻳﻜﻮﻥ ﺗﺎﺑﻌﺎ ‪ Function‬ﻭﻟﻴﺲ ﺇﺟﺮﺍﺋﻴﺔ ‪ Procedure‬ﻭﻟﻴﻜﻦ ﺇﲰﺔ "‪ ، " LeapYear‬ﻭﺳﻴﺒﺪﻭ ﺷﻜﻠﺔ ﺑﻌﺪ‬
‫ﺍﻹﻧﺘﻬﺎﺀ ﻛﺎﻟﺘﺎﱄ ‪:‬‬
‫;)'‪If (TheDate. LeapYear) then showmessage('Leap Year‬‬

‫ﻣﻨﻬﺞ ﺇﺧﺮﺍﺝ ﺍﻟﺘﺎﺭﻳﺦ ﺑﺸﻜﻞ ﻧﺼﻲ ﻣﺸﺎﺑﻪ ﳊﺎﻟﺔ ﺗﺎﺑﻊ ﺍﻟﺴﻨﺔ ﺍﻟﻜﺒﻴﺴﺔ ﻹﻧﺔ ﺳﻴﻌﻴﺪ ﻗﻴﻤﺔ ﻧﺼﻴﻪ ﻭﺍﺣﺪﺓ ‪ ،‬ﻭﺑﺎﻟﺘﺎﱄ ﺳﻴﻜﻮﻥ‬
‫ﺗﺎﺑﻌﺎ ﻭﺳﻴﻜﻮﻥ ﺷﻜﻠﺔ ﺑﻌﺪ ﺍﻹﻧﺘﻬﺎﺀ ﻛﺎﻟﺘﺎﱄ ‪:‬‬
‫;)‪showmessage(TheDate.GetText‬‬

‫‪ -‬ﻣﻨﻬﺞ ﺯﻳﺎﺩﺓ ﺍﻟﻴﻮﻡ ﻟﻴﺲ ﲝﺎﺟﺔ ﺃﺻﻼ ﻟﺒﺎﺭﺍﻣﺘﺮﺍﺕ ‪ ،‬ﻹﻥ ﻣﻘﺪﺍﺭ ﺍﻟﺰﻳﺎﺩﺓ ﳏﺪﺩﺓ ﺳﻠﻔﺎ ﺣﻴﺚ ﺳﻴﺰﻳﺪ ﺍﻟﺘﺎﺑﻊ ﻳﻮﻡ ﻭﺍﺣﺪ‬
‫ﻓﻘﻂ ﻋﻨﺪ ﻛﻞ ﻣﺮﺓ ﻳﺘﻢ ﺇﺳﺘﺪﻋﺎﺀﺓ ﻓﻴﻬﺎ ‪ ،‬ﻭﻟﻴﻜﻦ ﺇﲰﺔ " ‪"Increase‬‬

‫‪١٥‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻭﺇﺳﺘﺨﺪﺍﻣﺔ ﺳﻴﻜﻮﻥ ﲟﻨﺘﻬﻰ ﺍﻟﺴﻬﻮﻟﺔ ‪:‬‬


‫;‪TheDate.increase‬‬

‫ﺇﻥ ﻛﻞ ﻣﻦ ﺍﻹﺣﺪﺍﺙ ﺍﻟﺴﺎﺑﻘﺔ ﳚﺐ ﺃﻥ ﻳﻜﻮﻥ ﻣﺮﺋﻴﺎ ﻣﻦ ﻛﻞ ﺍﻟﻮﺣﺪﺍﺕ ﻭﻳﺴﺘﻄﻴﻊ ﺍﳌﺴﺘﺨﺪﻡ ﺇﺳﺘﺨﺪﺍﻣﺔ ﺑﺸﻜﻞ‬
‫ﺍﻟﺘﻮﺟﻴﺔ ‪. Public‬‬ ‫ﻃﺒﻴﻌﻲ‪ ،‬ﻭﺑﺎﻟﺘﺎﱄ ﳚﺐ ﺃﻥ ﻳﻌﺮﻑ ﲢﺖ‬

‫ﻭﻣﺎ ﺃﺻﺒﺤﻨﺎ ﻧﻌﺮﻓﺔ ﺍﻵﻥ ﺃﻧﻨﺎ ﳕﻠﻚ ﺻﻨﻒ ‪ Tdate‬ﻟﺔ ﺍﳌﻨﺎﻫﺞ ﺍﻟﻌﺎﻣﺔ ﺍﻟﺴﺎﺑﻘﺔ ﻭﺑﺎﻟﺘﺎﱄ ﺃﺻﺒﺢ ﺍﻟﺘﻌﺮﻳﻒ ﺳﻬﻼ ‪ ،‬ﻭﺣﱴ ﻫﺬﺓ‬
‫ﺍﳌﺮﺣﻠﺔ ﳝﻜﻨﻨﺎ ﺃﻥ ﻧﻜﺘﺐ ﺍﻟﺘﻌﺮﻳﻒ ﻛﺎﻟﺘﺎﱄ ‪:‬‬

‫‪type‬‬

‫‪TDate = class‬‬

‫‪public‬‬

‫;‪procedure SetValue (y, m, d: Integer); overload‬‬

‫;‪procedure SetValue (NewDate: TDateTime); overload‬‬

‫;‪function LeapYear: Boolean‬‬

‫;‪function GetText: string‬‬

‫;‪procedure Increase‬‬

‫;‪end‬‬

‫ﺍﳋﺼﺎﺋﺺ ﺍﳌﻄﻠﻮﺑﺔ ‪ Year‬ﻭ ‪ Month‬ﻭ ‪ Day‬ﲢﺘﺎﺝ ﺇﱃ ﻗﺮﺍﺀﺓ ﻭﻛﺘﺎﺑﺔ ﺑﺎﻟﺘﺄﻛﻴﺪ ‪ ،‬ﻭﺳﺄﺧﺘﺎﺭ ﻫﻨﺎ ﺍﳊﺎﻟﺔ ﺍﻟﻌﺎﻣﺔ ﻭﺃﺿﻊ ﺗﺎﺑﻊ‬
‫ﻟﻠﻘﺮﺍﺀﺓ ﻭﺇﺟﺮﺍﺋﻴﺔ ﻟﻠﻜﺘﺎﺑﺔ ‪.‬‬

‫ﻓﺈﺫﺍ ﲰﻴﻨﺎ ﺗﺎﺑﻊ ﺍﻟﻘﺮﺍﺀﺓ ‪ GetYear‬ﻭﺇﺟﺮﺍﺋﻴﺔ ﺍﻟﻜﺘﺎﺑﺔ ‪ SetYear‬ﺳﺘﺼﺒﺢ ﺍﻟﺘﻌﺎﺭﻳﻒ ﺍﻟﺜﻼﺛﺔ ﻛﺎﻟﺘﺎﱄ ‪:‬‬
‫;‪property Year: Integer read GetYear write SetYear‬‬

‫;‪property Month: Integer read GetMonth write SetMonth‬‬

‫;‪property Day: Integer read GetDay write SetDay‬‬

‫‪‬‬

‫ﺑﺎﻟﺘﺄﻛﻴﺪ ﲟﺎ ﺃﻥ ﺍﳋﻮﺍﺹ ﳚﺐ ﺃﻥ ﺗﻜﻮﻥ ﻇﺎﻫﺮﺓ ﻟﻠﻤﺴﺘﺨﺪﻡ ﻭﻟﺒﻘﻴﺔ ﺍﻟﻮﺣﺪﺍﺕ ﻓﻬﻲ ﰲ ﻗﺴﻢ ‪ Public‬ﻛﺬﻟﻚ ‪،‬‬

‫‪١٦‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

GetYear , ‫ﻭﺍﻟﺸﻲﺀ ﺍﳌﻬﻢ ﻫﻨﺎ ﻫﻮ ﺃﻥ ﺍﻟﺘﻮﺍﺑﻊ ﻭﺍﻹﺟﺮﺍﺀﺍﺕ ﺍﳋﺎﺻﺔ ﺑﺎﻟﻘﺮﺍﺀﺓ ﻭﺍﻟﻜﺘﺎﺑﺔ ﺍﻟﱵ ﺍﺳﺘﺨﺪﻣﺘﻬﺎ ﺍﳋﻮﺍﺹ ﺍﻟﺴﺎﺑﻘﺔ ﻣﺜﻞ‬
‫ ﻭﺑﺎﻟﺘﺎﱄ‬، ‫ ﻫﻲ ﻣﻨﺎﻫﺞ ﳏﻠﻴﺔ ﻭﻻﳚﺐ ﻋﻠﻰ ﺍﳌﺴﺘﺨﺪﻡ ﺃﻥ ﻳﺮﺍﻫﺎ ﻭﻳﺴﺘﻌﻤﻠﻬﺎ ﻹﻧﺔ ﻳﺴﺘﻌﻤﻞ ﺍﳋﺎﺻﺔ ﺍﻷﺳﺎﺳﻴﺔ ﻣﺒﺎﺷﺮﺓ‬SetYear
. ‫ ﺣﻴﺚ ﻟﻦ ﺗﻜﻮﻥ ﻣﺮﺋﻴﺔ ﺧﺎﺭﺝ ﻫﺬﺓ ﺍﻟﻮﺣﺪﺓ‬، private ‫ﺳﻨﻘﻮﻡ ﺑﺘﻌﺮﻳﻔﻬﺎ ﺑﺸﻜﻞ ﳏﻠﻲ ﺿﻤﻦ ﺍﻟﺘﻮﺟﻴﺔ‬

‫ ﻻ ﺗﻨﺴﻰ ﺃﻧﻚ ﺗﻀﺒﻂ‬، ‫ﺑﻘﻲ ﻟﺪﻳﻨﺎ ﺍﻵﻥ ﺷﻲﺀ ﻭﺣﻴﺪ ﱂ ﻧﺄﺧﺬﺓ ﺑﺎﳊﺴﺒﺎﻥ ﻭﻫﻮ ﺍﳌﺘﺤﻮﻝ ﺍﻟﺬﻱ ﺳﻮﻑ ﳔﺰﻥ ﻗﻴﻤﺔ ﺍﻟﺘﺎﺭﻳﺦ ﻓﻴﺔ‬
. ‫ﻭﺑﺎﻟﺘﺎﱄ ﳓﻦ ﲝﺎﺟﺔ ﳌﺘﺤﻮﻝ ﳊﻔﻆ ﺍﻟﺘﺎﺭﻳﺦ‬، ‫ﻗﻴﻤﺔ ﺍﻟﺼﻨﻒ ﻣﺮﺓ ﻭﺍﺣﺪﺓ ﰒ ﺗﺴﺘﺪﻋﻲ ﺍﳌﻨﺎﻫﺞ ﺍﻟﺴﺎﺑﻘﺔ ﻟﻠﺘﺎﺭﻳﺦ ﺍﶈﻔﻮﻅ ﺿﻤﻨﺔ‬
Private ‫ ﻭﻃﺒﻌﺎ ﻻﺣﻈﺖ ﺃﻧﺔ ﳚﺐ ﺃﻥ ﻳﻌﺮﻑ ﳏﻠﻴﺎ ﺿﻤﻦ ﻗﺴﻢ‬، TdateTime ‫ﻣﻦ ﺍﻟﻨﻤﻂ‬fDate ‫ﻭﻟﻴﻜﻦ ﻫﺬﺍ ﺍﳌﺘﺤﻮﻝ ﻫﻮ‬
. ‫ﻛﺬﻟﻚ‬

: ‫ ﻛﺎﻟﺘﺎﱄ‬Interface ‫ﺃﺻﺒﺢ ﺍﻵﻥ ﺷﻜﻞ ﺍﻟﺘﻌﺮﻳﻒ ﺍﻟﻨﻬﺎﺋﻲ ﺍﻟﺬﻱ ﺳﻨﻀﻌﺔ ﰲ ﻗﺴﻢ ﺍﻟـ‬
type

TDate = class

private

fDate: TDateTime;

procedure SetDay(const Value: Integer);

procedure SetMonth(const Value: Integer);

procedure SetYear(const Value: Integer);

function GetDay: Integer;

function GetMonth: Integer;

function GetYear: Integer;

public

procedure SetValue (y, m, d: Integer); overload;

procedure SetValue (NewDate: TDateTime); overload;

function LeapYear: Boolean;

function GetText: string;

procedure Increase;

property Year: Integer read GetYear write SetYear;

property Month: Integer read GetMonth write SetMonth;

property Day: Integer read GetDay write SetDay;

١٧
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫;‪end‬‬

‫ﻭﺑﻘﻲ ﻋﻠﻴﻨﺎ ﻛﺘﺎﺑﺔ ﺃﺟﺴﺎﻡ ﺍﳌﻨﺎﻫﺞ ﰲ ﻗﺴﻢ ﺍﻟـ ‪. implementation‬‬

‫ﺗﺬﻛﲑ ‪ :‬ﻟﻜﺘﺎﺑﺔ ﺃﺟﺴﺎﻡ ﺍﳌﻨﺎﻫﺞ ﻧﻀﻴﻒ ﺇﺳﻢ ﺍﻟﺼﻨﻒ ﻣﻔﺼﻮﻻ ﺑﻨﻘﻄﺔ ﻋﻦ ﺇﺳﻢ ﺍﳌﻨﻬﺞ ﰲ ﺍﻟﺘﺮﻭﻳﺴﺔ ‪ .‬ﻣﺜﺎﻝ ‪:‬‬
‫;)‪procedure TDate.SetValue (y, m, d: Integer‬‬

‫‪begin‬‬

‫ﻻﺣﻆ ﺇﺳﻢ ﺍﻟﺼﻨﻒ ﻗﺒﻞ ﺇﺳﻢ ﺍﳌﻨﻬﺞ ‪... //‬‬

‫;‪end‬‬

‫‪DateUtils‬‬ ‫ﺃﻣﺎ ﺷﻔﺮﺓ ﺍﳌﻨﺎﻫﺞ ﻓﻬﻲ ﺑﻐﺎﻳﺔ ﺍﻟﺴﻬﻮﻟﺔ ﻭﳝﻜﻦ ﺍﻹﻋﺘﻤﺎﺩ ﻋﻠﻰ ﺑﻌﺾ ﺗﻌﻠﻴﻤﺎﺕ ﺍﻟﺘﺎﺭﻳﺦ ﺍﳌﻌﺮﻓﺔ ﰲ ﺍﻟﻮﺣﺪﺓ‬

‫;)‪fDate := EncodeDate (y, m, d‬‬


‫ﻳﻘﻮﻡ ﺑﺘﺤﻮﻳﻞ ﺛﻼﺙ ﻣﺘﺤﻮﻻﺕ ﺻﺤﻴﺤﺔ ﺗﺪﻝ ﻋﻠﻰ ﺍﻟﻴﻮﻡ ﻭﺍﻟﺸﻬﺮ‬
‫ﻭﺍﻟﺴﻨﺔ ﺇﱃ ﻣﺘﺤﻮﻝ ﻣﻦ ﺍﻟﻨﻮﻉ ‪. TdateTime‬‬

‫;)‪S:= DateToStr (fDate‬‬


‫ﻳﻘﻮﻡ ﺑﺎﻟﺘﺤﻮﻳﻞ ﻣﻦ ﺍﻟﻨﻤﻂ ‪ TdateTime‬ﺇﱃ ﺍﻟﻨﻤﻂ ‪، String‬‬
‫)ﻣﺸﺎﺑﺔ ﻟـ ‪ InttoStr‬ﻣﺜﻼ(‬

‫;)‪B:= IsInLeapYear(fDate‬‬
‫ﻳﻌﻴﺪ ﻗﻴﻤﺔ ﺑﻮﻟﻴﺎﻧﻴﺔ ﺇﺫﺍ ﻛﺎﻧﺖ ﺍﻟﺴﻨﺔ ﻛﺒﻴﺴﺔ ﺃﻭﻻ‬

‫;)‪fDate := RecodeYear (fDate, Value‬‬


‫ﻳﻀﺒﻂ ﻗﻴﻤﺔ ﺍﻟﺴﻨﺔ ﰲ ﺍﻟﺘﺎﺭﻳﺦ ﻋﻦ ﻃﺮﻳﻖ ﲤﺮﻳﺮ ﺍﻟﻘﻴﻤﺔ ﺍﳉﺪﻳﺪﺓ‬
‫ﻟﻠﺴﻨﺔ ﺑﺎﳌﺘﺤﻮﻝ ‪Value‬‬

‫;)‪Result := YearOf (fDate‬‬


‫ﻳﻌﻴﺪ ﻗﻴﻤﺔ ﺍﻟﺴﻨﺔ ﰲ ﻣﺘﺤﻮﻝ ﺍﻟﺘﺎﺭﻳﺦ ‪fDate‬‬

‫ﺗﺼﺒﺢ ﺷﻔﺮﺓ ﺍﻟﻮﺣﺪﺓ ﻛﺎﻣﻠﺔ ‪:‬‬


‫;‪unit Dates‬‬

‫‪interface‬‬

‫‪uses‬‬ ‫;‪SysUtils‬‬

‫‪type‬‬

‫‪TDate = class‬‬

‫‪private‬‬

‫;‪fDate: TDateTime‬‬

‫‪١٨‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

procedure SetDay(const Value: Integer);

procedure SetMonth(const Value: Integer);

procedure SetYear(const Value: Integer);

function GetDay: Integer;

function GetMonth: Integer;

function GetYear: Integer;

public

procedure SetValue (y, m, d: Integer); overload;

procedure SetValue (NewDate: TDateTime); overload;

function LeapYear: Boolean;

function GetText: string;

procedure Increase;

property Year: Integer read GetYear write SetYear;

property Month: Integer read GetMonth write SetMonth;

property Day: Integer read GetDay write SetDay;

end;

implementation

uses

DateUtils;

procedure TDate.SetValue (y, m, d: Integer);

begin

fDate := EncodeDate (y, m, d);

end;

procedure TDate.SetValue(NewDate: TDateTime);

begin

fDate := NewDate;

end;

function TDate.GetText: string;

begin

Result := DateToStr (fDate);

end;

١٩
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

procedure TDate.Increase;

begin

fDate := fDate + 1;

end;

function TDate.LeapYear: Boolean;

begin

// from DateUtils

Result := IsInLeapYear(fDate);

end;

procedure TDate.SetDay(const Value: Integer);

begin

fDate := RecodeDay (fDate, Value);

end;

procedure TDate.SetMonth(const Value: Integer);

begin

fDate := RecodeMonth (fDate, Value);

end;

procedure TDate.SetYear(const Value: Integer);

begin

fDate := RecodeYear (fDate, Value);

end;

function TDate.GetDay: Integer;

begin

Result := DayOf (fDate);

end;

function TDate.GetMonth: Integer;

begin

Result := MonthOf (fDate);

٢٠
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫;‪end‬‬

‫;‪function TDate.GetYear: Integer‬‬

‫‪begin‬‬

‫;)‪Result := YearOf (fDate‬‬

‫;‪end‬‬

‫‪end.‬‬

‫ﻣﻼﺣﻈﺎﺕ ﺣﻮﻝ ﺍﳋﺼﺎﺋﺺ ‪:‬‬

‫ﳝﻜﻨﻨﺎ ﺣﺬﻑ ﺍﳉﺰﺀ ﺍﳋﺎﺹ ﺑﺎﻟﻜﻠﻤﺔ ﺍﳌﻔﺘﺎﺣﻴﺔ ‪ Write‬ﻣﻦ ﺗﻌﺮﻳﻒ ﺍﳋﺎﺻﻴﺔ ﻟﻨﺤﺼﻞ ﻋﻠﻰ ﺧﺎﺻﻴﺔ ﻟﻠﻘﺮﺍﺀﺓ ﻓﻘﻂ )‪(read-only‬‬
‫‪ ،‬ﻭﻋﻨﺪﻫﺎ ﺳﻴﻮﻟﺪ ﺍﳌﺘﺮﺟﻢ ﺧﻄﺄ ﺇﺫﺍ ﺣﺎﻭﻝ ﺍﳌﺴﺘﺨﺪﻡ ﺗﻐﲑ ﻗﻴﻤﺔ ﺧﺎﺻﻴﺔ ﻟﻠﻘﺮﺍﺀﺓ ﻓﻘﻂ ‪.‬‬

‫ﳓﻮﻳﺎ ﳝﻜﻨﻚ ﺣﺬﻑ ﺍﳉﺰﺀ ‪ read‬ﻭﺍﳊﺼﻮﻝ ﻋﻠﻰ ﺧﺎﺻﺔ ﻟﻠﻜﺘﺎﺑﺔ ﻓﻘﻂ ﺩﻭﻥ ﺧﻄﺄ ﻣﻦ ﺍﳌﺘﺮﺟﻢ ‪ ،‬ﻭﻟﻜﻦ ﺫﻟﻚ ﻻ ﻳﻌﺘﱪ ﺗﻔﻜﲑﺍ‬
‫ﻧﻈﺎﻣﻴﺎ ﻭﻟﻴﺲ ﻟﻪ ﺇﺳﺘﺨﺪﺍﻣﺎﺕ ﺣﻘﻴﻘﻴﺔ ‪.‬‬

‫ﺑﻴﺌﺔ ﺍﻟﺪﻟﻔﻲ ﺗﺘﻌﺎﻣﻞ ﺑﻄﺮﻳﻘﺔ ﺧﺎﺻﻪ ﻣﻊ ﺧﻮﺍﺹ ﺯﻣﻦ‪-‬ﺍﻟﺘﺼﻤﻴﻢ ‪ ،‬ﻭﺍﻟﱵ ﺗﻈﻬﺮ ﰲ ﺿﺎﺑﻂ ﺍﻟﻜﺎﺋﻨﺎﺕ ﺃﺛﻨﺎﺀ ﺍﻟﺘﺼﻤﻴﻢ ‪ .‬ﻭﻳﺴﺘﺨﺪﻡ‬
‫ﻣﻌﻬﺎ ﳏﺪﺩ ﺍﻟﻮﺻﻮﻝ ‪ published‬ﺍﻟﺬﻱ ﺳﺘﻌﺮﻑ ﻋﻨﺔ ﰲ ﻗﺴﻢ ﺑﻨﺎﺀ ﺍﻟﻌﻨﺎﺻﺮ ﺍﳉﺪﻳﺪﺓ ﰲ ﻫﺬﺍ ﺍﻟﻜﺘﺎﺏ ‪.‬‬

‫ﺗﺴﻤﻰ ﺍﳋﻮﺍﺹ ﺍﳌﻌﺮﻓﺔ ﺑﺎﶈﺪﺩ ‪ Public‬ﺧﻮﺍﺹ ﺯﻣﻦ‪-‬ﺍﻟﺘﻨﻔﻴﺬ )‪ ، (design-time properties‬ﻭﻫﻲ ﳐﺼﺼﺔ ﻟﻺﺳﺘﺨﺪﺍﻡ‬
‫ﺿﻤﻦ ﺷﻘﺮﺓ ﺍﻟﱪﻧﺎﻣﺞ ‪.‬‬

‫ﺗﻨﺒﻴﺔ ‪ :‬ﺑﻌﺾ ﺍﻟﺘﻮﺟﻴﻬﺎﺕ ﺍﻹﺿﺎﻓﻴﺔ ﻟﻠﺨﺼﺎﺋﺺ )ﻣﺜﻞ ‪ stored‬ﻭ‪ (default‬ﺳﻨﺘﻌﺮﺽ ﳍﺎ ﻳﺎﻟﻔﺼﻮﻝ ﺍﻟﻘﺎﺩﻣﺔ ‪.‬‬

‫ﻣﻼﺣﻈﺔ ‪ :‬ﳝﻜﻦ ﻗﺮﺍﺀﺓ ﻗﻴﻤﺔ ﺍﳋﺎﺻﻴﺔ ‪ ،‬ﺃﻭ ﺍﻟﻜﺘﺎﺑﺔ ‪‬ﺎ ‪ ،‬ﺃﻭ ﺣﱴ ﺇﺳﺘﺨﺪﺍﻣﻬﺎ ﺿﻤﻦ ﺍﻟﺘﻌﺎﺑﲑ ﺍﳌﺨﺘﻠﻔﺔ ‪ .‬ﻭﻟﻜﻦ ﻟﻴﺲ ﻣﻦ‬
‫ﺍﻟﻀﺮﻭﺭﻱ ﺃﻥ ﻳﻘﺒﻞ ﲤﺮﻳﺮﻫﺎ ﻛﻤﺘﻐﲑ ﺇﱃ ﻣﻨﻬﺞ ﻣﺎ ‪ ،‬ﻹ‪‬ﺎ ﻟﻴﺴﺖ ﻣﻮﺍﻗﻊ ﺫﺍﻛﺮﺓ ﻣﺜﻞ ﺍﳌﺘﺤﻮﻻﺕ ‪.‬‬

‫‪٢١‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﳌﺰﻳﺪ ﻋﻦ ﺍﻟﺘﻐﻠﻴﻒ ‪:‬‬


‫ﺍﻟﺘﻐﻠﻴﻒ ﻣﻊ ﺍﻷﺷﻜﺎﻝ‬

‫ﺇﺣﺪﻯ ﺍﻷﻓﻜﺎﺭ ﺍﳌﻔﺘﺎﺣﻴﺔ ﻟﻠﺘﻐﻠﻴﻒ ﻫﻲ ﺗﻘﻠﻴﻞ ﺍﳌﺘﻐﲑﺍﺕ ﺍﻟﻌﺎﻣﺔ ﺍﳌﺴﺘﺨﺪﻣﻪ ﻣﻦ ﻛﺎﻣﻞ ﺍﻟﱪﻧﺎﻣﺞ ‪ ،‬ﳝﻜﻦ ﺍﻟﺪﺧﻮﻝ ﺇﱃ ﺍﳌﺘﻐﲑ ﺍﻟﻌﺎﻡ‬
‫ﻣﻦ ﺃﻱ ﺟﺰﺀ ﻣﻦ ﺍﻟﱪﻧﺎﻣﺞ ‪ ،‬ﻟﺬﻟﻚ ﻓﺈﻥ ﺗﻐﻴﲑﺍ ﰲ ﻣﺘﺤﻮﻝ ﻋﺎﻡ ﺳﻴﺆﺛﺮ ﻋﻠﻰ ﻛﺎﻣﻞ ﺍﻟﱪﻧﺎﻣﺞ ‪ ،‬ﰲ ﺣﲔ ﺃﻧﻚ ﻋﻨﺪﻣﺎ ﺗﻐﲑ ﲤﺜﻴﻞ‬
‫ﺃﺣﺪ ﺣﻘﻮﻝ ﺻﻨﻒ ﻣﺎ ‪ ،‬ﻓﺈﻧﻚ ﲝﺎﺟﺔ ﻟﺘﻐﲑ ﺷﻔﺮﺍﺕ ﺑﻌﺾ ﺍﳌﻨﺎﻫﺞ ﺍﻟﱵ ﺗﺴﺘﺨﺪﻣﺔ ﻓﻘﻂ ‪،‬‬

‫ﻟﺬﻟﻚ ﻧﺴﺘﻄﻴﻊ ﺍﻟﻘﻮﻝ ﺃﻥ ﺇﺧﻔﺎﺀ ﺍﳌﻌﻠﻮﻣﺎﺕ ﻳﺸﲑ ﺇﱃ ﺗﻐﻠﻴﻒ ﺍﻟﺘﻐﻴﲑﺍﺕ ‪.‬‬

‫ﻭﻟﺘﻮﺿﻴﺢ ﻫﺬﺓ ﺍﻟﻔﻜﺮﺓ ﺳﺄﻗﺘﺮﺡ ﻣﺜﺎﻻ ‪ ،‬ﻟﺪﻳﻨﺎ ﺑﺮﻧﺎﻣﺞ ﻟﻪ ﻋﺪﺓ ﺃﺷﻜﺎﻝ )‪ ، (Multiple Forms‬ﻧﺴﺘﻄﻴﻊ ﺃﻥ ﳒﻌﻞ ﺑﻌﺾ‬
‫ﺍﻟﺒﻴﺎﻧﺎﺕ ﻣﺘﺎﺣﺔ ﻟﻜﻞ ﺍﻷﺷﻜﺎﻝ ﺑﺘﻌﺮﻳﻔﻬﺎ ﰲ ﻗﺴﻢ ﺍﻟﻮﺍﺟﻬﺔ )‪ (Interface‬ﻹﺣﺪﻯ ﺍﻷﺷﻜﺎﻝ‬
‫‪var‬‬
‫;‪Form1: TForm1‬‬

‫;‪nClicks: Integer‬‬

‫ﺳﻴﻌﻤﻞ ﺍﻟﱪﻧﺎﻣﺞ ﺑﺸﻜﻞ ﺟﻴﺪ ‪‬ﺬﺓ ﺍﻟﻄﺮﻳﻘﺔ ‪ ،‬ﻭﻟﻜﻦ ﻋﻠﻴﻚ ﺃﻥ ﺗﻌﺮﻑ ﺑﺈﻥ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﻟﱵ ﻋﺮﻓﻨﺎﻫﺎ ﻫﻨﺎ ﻟﻴﺴﺖ ﺗﺎﺑﻌﺔ ﻟﻠﺸﻜﻞ‬
‫ﺍﻟﺬﻱ ﻋﺮﻓﻨﺎﻫﺎ ﻓﻴﺔ ‪ ،‬ﺑﻞ ﺃﺻﺒﺤﺖ ﺗﺎﺑﻌﺔ ﻟﻜﺎﻣﻞ ﺍﻟﱪﻧﺎﻣﺞ ‪ ،‬ﻓﺈﺫﺍ ﺃﻧﺸﺄﻧﺎ ﺷﻜﻼﻥ ﻣﻦ ﻧﻔﺲ ﺍﻟﺼﻨﻒ ﻓﺈ‪‬ﻤﺎ ﺳﻴﺘﺸﺎﺭﻛﺎﻥ ﺍﻟﺒﻴﺎﻧﺎﺕ‬
‫ﺍﳌﻌﺮﻓﺔ ﰲ ﻗﺴﻢ ﺍﻟﻮﺍﺟﻬﺔ ﻧﻔﺴﻬﺎ ‪ .‬ﻣﺜﻼ ﻟﻮ ﻗﻤﻨﺎ ﺑﺈﻧﺸﺎﺀ ﻋﺪﺓ ﻧﺴﺦ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ Tform3‬ﰲ ﺯﻣﻦ ﺍﻟﺘﺸﻐﻴﻞ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﻟﺒﺎﱐ ‪، Create‬‬
‫ﺳﻴﺼﺒﺢ ﻟﺪﻳﻨﺎ ﻋﺪﺓ ﺃﺷﻜﺎﻝ ﻟﻨﻔﺲ ﺍﻟﺼﻨﻒ ‪ ،‬ﻛﻴﻒ ﳒﻌﻞ ﺑﻴﺎﻧﺎﺕ ﻣﺎ ﺧﺎﺻﺔ ﺑﺈﺣﺪﺍﻫﺎ ﻭﻣﺮﺋﻴﺔ ﻣﻦ ﺑﻘﻴﺔ ﺍﻟﱪﻧﺎﻣﺞ ؟‬

‫ﻓﺈﺫﺍ ﺃﺭﺩﺕ ﺃﻥ ﻳﻜﻮﻥ ﻟﻜﻞ ﻭﺍﺣﺪ ﻣﻨﻬﻤﺎ ﻧﺴﺨﺘﺔ ﺍﳋﺎﺻﺔ ﻣﻦ ﺍﻟﺒﻴﺎﻧﺎﺕ ‪ ،‬ﻓﻌﻠﻴﻚ ﺇﺿﺎﻓﺔ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺇﱃ ﺻﻨﻒ ﺍﻟﻔﻮﺭﻡ ﻧﻔﺴﺔ‬
‫ﻭﺑﺎﻟﺘﺎﱄ ﺳﻴﻨﺴﺦ ﻛﻞ ﺷﻜﻞ ﻧﺴﺨﺔ ﺧﺎﺻﺔ ﺑﻪ ‪.‬‬
‫‪type‬‬
‫)‪TForm1 = class(TForm‬‬
‫‪public‬‬
‫;‪nClicks: Integer‬‬
‫;‪end‬‬

‫ﻣﻼﺣﻈﺔ ‪ :‬ﻳﺴﺘﺨﺪﺍﻡ ﺫﻟﻚ ﺑﻜﺜﺮﺓ ﰲ ﺗﻄﺒﻴﻘﺎﺕ ‪ MDI‬ﲝﻴﺚ ﳓﺘﺎﺝ ﻣﺘﺤﻮﻻﺕ ﺧﺎﺻﺔ ﺑﻜﻞ ﻓﻮﺭﻡ ﻭﻻ ﻧﻀﻤﻦ ﻣﺎ ﻫﻮ ﻋﺪﺩ‬
‫ﺍﻷﺷﻜﺎﻝ ﺍﻟﱵ ﺳﻴﻨﺸﺌﻬﺎ ﺍﳌﺴﺘﺨﺪﻡ ﰲ ﺯﻣﻦ ﺍﻟﺘﺼﻤﻴﻢ ‪ ،‬ﺃﻭ ﰲ ﺗﻄﺒﻴﻘﺎﺕ ﺍﻟﻮﻳﺐ ﻣﺜﻼ ﲝﻴﺚ ﳓﺘﺎﺝ ﺟﻠﺴﺔ ﻟﻜﻞ ﻣﺴﺘﺨﺪﻡ ﻣﻮﺟﻮﺩ‬
‫ﺣﺎﻟﻴﺎ ‪ ،‬ﻭﻟﺔ ﺇﺳﺘﺨﺪﺍﻣﺎﺕ ﻛﺜﲑﺓ ﺃﺧﺮﻯ ‪.‬‬

‫‪٢٢‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻣﻼﺣﻈﺔ ‪ :‬ﺍﻟﺼﻨﻒ ﺍﻟﺴﺎﺑﻖ ﻳﺴﺘﺨﺪﻡ ﺍﻟﺒﻴﺎﻧﺎﺕ ﻋﻠﻰ ﺃ‪‬ﺎ ﻋﺎﻣﺔ ‪ Public‬ﻭﻣﻦ ﺃﺟﻞ ﺗﻐﻠﻴﻒ ﺟﻴﺪ ﻋﻠﻴﻚ ﺃﻥ ﲡﻌﻞ ﺍﻟﺒﻴﺎﻧﺎﺕ‬
‫‪ Private‬ﻭﺃﻥ ﺗﻀﻴﻒ ﻟﻘﺴﻢ ‪ Public‬ﻣﻨﺎﻫﺞ ﺧﺎﺻﺔ ﻟﻠﻮﺻﻮﻝ ﺇﻟﻴﻬﺎ ‪ ،‬ﻛﻤﺎ ﺗﻌﻠﻤﻨﺎ ﺳﺎﺑﻘﺎ ‪.‬‬

‫ﻭﺑﻴﺒﺴﺎﻃﺔ ﺩﻋﻨﺎ ﻧﻀﻴﻒ ﺧﺎﺻﻴﺔ ﺟﺪﻳﺪﺓ ﺇﱃ ﺻﻨﻒ ﺍﻟﺸﻜﻞ ﻭﻧﺮﻳﺢ ﺑﺎﻟﻨﺎ ﺃﻛﺜﺮ ‪ ،‬ﲝﻴﺚ ﻛﻠﻤﻨﺎ ﺃﺣﺘﺠﻨﺎ ﻟﺘﻐﻴﻴﲑ ﺃﻭ ﻗﺮﺍﺀﺓ ﺍﻟﺒﻴﺎﻧﺎﺕ‬
‫ﻣﻦ ﺷﻜﻞ ﺁﺧﺮ ﻧﺴﺘﺨﺪﻡ ﺍﳋﺎﺻﻴﺔ ﻧﻔﺴﻬﺎ ‪ ،‬ﻧﻌﻴﺪ ﻛﺘﺎﺑﺔ ﺍﻟﺘﻌﺮﻳﻒ ﺍﻟﺴﺎﺑﻖ ﻟﻴﺼﺒﺢ ﺑﺎﻟﺸﻜﻞ ‪:‬‬

‫‪type‬‬
‫)‪TForm1 = class(TForm‬‬
‫‪private‬‬
‫;‪FClicks: Integer‬‬
‫‪public‬‬
‫;‪property nClicks: Integer read FClicks write SetClicks‬‬
‫;‪end‬‬

‫ﺭﺍﺟﻊ ﺍﳌﺜﺎﻝ ﺍﳌﺮﻓﻖ ﻣﻊ ﺍﻷﻣﺜﻠﺔ ‪ ،‬ﻭﻻﺣﻆ ﺃﻧﻨﺎ ﺃﻧﺸﺄﻧﺎ ﻋﺪﺓ ﺃﺷﻜﺎﻝ ﻣﻦ ﻧﻔﺲ ﺍﻟﺼﻨﻒ ﻭﻟﻜﻞ ﻭﺍﺣﺪ ﻣﻨﻬﺎ ﻋﺪﺍﺩ ﻧﻘﺮﺍﺕ ﺧﺎﺹ ‪.‬‬

‫ﻣﻼﺣﻈﺔ ‪ :‬ﺧﺎﺻﻴﺔ ﺯﻣﻦ‪-‬ﺍﻟﺘﺸﻐﻴﻞ ﺍﻟﱵ ﺃﺿﻔﻨﺎﻫﺎ ﻟﻦ ﺗﻀﺎﻑ ﺇﱃ ﺿﺎﺑﻂ ﺍﻟﻜﺎﺋﻨﺎﺕ ‪ ،‬ﺑﻞ ﳝﻜﻦ ﺇﺳﺘﺨﺪﺍﻣﻬﺎ ﺩﺍﺧﻞ ﺍﻟﺸﻔﺮﺓ ﻓﻘﻂ‪.‬‬

‫ﺭﺍﺟﻊ ﺃﻳﻀﺎ ‪ :‬ﻣﺜﺎﻝ ﺍﳌﻘﺎﺭﻧﺔ ﺍﳌﺮﻓﻖ ‪ ،‬ﻟﻠﺘﺄﻛﺪ ﻣﻦ ﺇﺗﻘﺎﻥ ﺍﻟﺘﻌﺎﻣﻞ ﻣﻊ ﻫﺬﺓ ﺍﻟﻔﻜﺮﺓ ﺑﺸﻜﻞ ﺟﻴﺪ ‪ ،‬ﻭﻋﺪﻡ ﺍﻟﻮﻗﻮﻉ ﰲ ﻣﻄﺒﺎ‪‬ﺎ ‪.‬‬

‫ﺍﻟﺒﺎﱐ ‪: Constructor‬‬

‫ﺍﻟﺒﺎﱐ ﻫﻮ ﻣﻨﻬﺞ ﺧﺎﺹ ﻳﺴﺘﺨﺪﻡ ﳊﺠﺰ ﺍﻟﺬﺍﻛﺮﺓ ﳌﻨﺘﺴﺦ ﻣﻦ ﺻﻨﻒ ﻟﻴﺼﺒﺢ ﺟﺎﻫﺰﺍﹰ ﻟﻺﺳﺘﺨﺪﺍﻡ ‪ ،‬ﻭﻛﻨﺎ ﻗﺪ ﲰﻴﻨﺎﻩ ﺍﳌﻨﻬﺞ‬
‫‪ Create‬ﰲ ﻣﺎﻣﻀﻰ ‪ ،‬ﺍﳊﻘﻴﻘﺔ ﺍﻟﱵ ﺃﺭﻳﺪﻙ ﺃﻥ ﺗﻌﺮﻓﻬﺎ ﻋﻦ ﺍﻟﺒﺎﱐ ﺃﻧﺔ ﻳﻌﻴﺪ ﺍﻟﻐﺮﺽ ﻛﻘﻴﻤﺔ ﺟﺎﻫﺰﺓ ﻟﻺﺳﺘﺨﺪﺍﻡ ﺣﻴﺚ ﻧﺴﺘﻄﻴﻊ‬
‫ﻧﺴﻴﺔ ﺇﱃ ﻣﺘﺤﻮﻝ ﻣﻮﺟﻮﺩ ﻟﻜﻲ ﻧﺴﺘﺨﺪﻣﺔ ﻻﺣﻘﺎ ‪ .‬ﺃﻱ ﻛﺄﻧﺔ ﺗﺎﺑﻊ ﻗﻴﻤﺘﺔ ﺍﳌﻌﺎﺩﺓ ﻫﻲ ﺍﻟﻐﺮﺽ ﻧﻔﺴﺔ ‪ ،‬ﻣﺜﻼ ‪:‬‬
‫;‪var B:Tbutton‬‬

‫‪begin‬‬

‫;)‪B:=TButton.Create(Application‬‬

‫ﺃﺟﻞ ﺍﻟﺼﻨﻒ ‪Tbutton‬‬ ‫ﻻﺣﻆ ﺃﻥ ﺍﻟﺒﺎﱐ ﻳﺴﺘﺨﺪﻡ ﻣﻊ ﺍﻟﺼﻨﻒ ﻟﻜﻲ ﻳﻌﻴﺪ ﺍﻟﻐﺮﺽ ‪ ،‬ﻣﺜﻼ ﻫﻨﺎ ﺃﺳﺘﺪﻋﻴﻨﺎ ﺍﻟﺒﺎﱐ ﻣﻦ‬

‫ﻭﺍﻟﻨﺘﻴﺠﺔ ﻧﻀﻌﻬﺎ ﺑﺎﳌﺘﺤﻮﻝ ‪ ، B‬ﻭﻧﺴﺘﻄﻴﻊ ﺇﺳﺘﺨﺪﺍﻡ ‪ B‬ﻻﺣﻘﺎ ﻟﻠﺘﻌﺎﻣﻞ ﻣﻊ ﺍﻟﻐﺮﺽ ﺍﻟﻨﺎﺗﺞ ﻛﻤﺎ ﻧﺘﻌﺎﻣﻞ ﻣﻊ ﺃﻱ ﺯﺭ ‪.‬‬

‫‪٢٣‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻭﺍﻟﺸﻔﺮﺓ ﺍﻟﻜﺎﻣﻠﺔ ﻟﺬﻟﻚ ﻫﻲ ‪:‬‬


‫;‪var B:Tbutton‬‬

‫‪begin‬‬

‫;)‪b:=TButton.Create(Application‬‬

‫;‪b.Parent:=form1‬‬

‫;‪b.Left:=10‬‬

‫;‪b.Top:=10‬‬

‫;'‪b.Caption:='Hi‬‬

‫;‪end‬‬

‫ﺑﻨﺎﺀ ﺑﺎﱐ ﺟﺪﻳﺪ ‪:‬‬

‫ﺇﻥ ﺑﻴﺎﻧﺎﺕ ﺃﻱ ﻏﺮﺽ ﺟﺪﻳﺪ ﺗﻜﻮﻥ ﻣﻀﺒﻮﻃﺔ ﻟﻠﺼﻔﺮ ‪ ،‬ﻓﺈﺫﺍ ﺃﺭﺩﺕ ﺃﻥ ﺗﺒﺪﺃ ﻫﺬﺓ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺑﻘﻴﻢ ﳏﺪﺩﺓ ﻋﻠﻴﻚ ﻛﺘﺎﺑﺔ ﺑﺎﱐ ﺟﺪﻳﺪ‬
‫ﳍﺎ ﲢﺪﺩ ﻓﻴﺔ ﺍﻟﻘﻴﻢ ﺍﻹﻓﺘﺮﺍﺿﻴﺔ ﺍﻟﱵ ﻳﺒﺪﺃ ﺍﻟﻐﺮﺽ ‪‬ﺎ ‪،‬‬

‫ﻟﺒﻨﺎﺀ ﺑﺎﱐ ﺟﺪﻳﺪ ﻧﺴﺘﺨﺪﻡ ﺍﻟﻜﻠﻤﺔ ﺍﳌﻔﺘﺎﺣﻴﺔ ‪ constructor‬ﰲ ﺑﺪﺍﻳﺔ ﺗﻌﺮﻳﻒ ﻣﻨﻬﺠﻨﺎ ﺍﳉﺪﻳﺪ )ﺑﺪﻻ ﻣﻦ ‪ Function‬ﺃﻭ‬
‫‪ . (Procedure‬ﰲ ﺍﳊﻘﻴﻘﺔ ﺗﺴﺘﻄﻴﻊ ﺃﻥ ﺗﺴﺘﺨﺪﻡ ﺃﻱ ﺇﺳﻢ ﳍﺬﺍ ﺍﻟﺒﺎﱐ ﻭﻟﻦ ﻳﻌﻄﻴﻚ ﺍﳌﺘﺮﺟﻢ ﺃﻱ ﺧﻄﺄ ﳓﻮﻱ ‪ ،‬ﻭﻟﻜﻦ ﺇﺫﺍ ﺃﺭﺩﺕ‬
‫ﺭﺃﻳﻲ ﻻﺗﺴﺘﺨﺪﻡ ﺃﺑﺪﺍ ﺇﺳﻢ ﻏﲑ ﺍﻹﺳﻢ ﺍﻟﻘﻴﺎﺳﻲ ﻟﻪ ‪ ،‬ﻭﺍﻟﺬﻱ ﺃﺻﺒﺤﺖ ﺗﻌﺮﻓﺔ ﺟﻴﺪﺍ ﻭﻫﻮ "‪ . "Create‬ﻹﻥ ﺃﻱ ﻣﱪﻣﺞ ﺁﺧﺮ ﻟﻦ‬
‫ﻳﺘﻌﺮﻑ ﻋﻠﻰ ﺍﻟﺒﺎﱐ ﺍﳋﺎﺹ ﺑﻚ ﻭﳛﺴﻦ ﺇﺳﺘﺨﺪﺍﻣﺔ ‪ ،،‬ﺗﺬﻛﺮ ﳓﻦ ﻫﻨﺎ ﻟﻨﺘﻌﻠﻢ ﻛﺘﺎﺑﺔ ﺑﺮﺍﻣﺞ ﻗﻴﺎﺳﻴﺔ ﻛﻤﺎ ﻳﻜﺘﺒﻬﺎ ﺍﳋﱪﺍﺀ‬
‫ﻭﺍﶈﺘﺮﻓﻮﻥ ‪.‬‬

‫ﻣﻼﺣﻈﺔ ‪ :‬ﻋﻨﺪﻣﺎ ﺗﻌﺮﻑ ﺑﺎﱐ ﺟﺪﻳﺪ ﻟﺼﻨﻒ ﻣﻮﺟﻮﺩ ﺃﻭ ﻟﺼﻨﻒ ﻣﺴﺘﻖ ‪ ،‬ﻓﺈﻥ ﺍﻟﺒﺎﱐ ﺍﻟﻘﺪﱘ ﻟﻦ ﻳﺼﺒﺢ ﻣﺘﺎﺣﺎ ﻭﺳﻴﺼﺒﺢ‬
‫ﺇﺳﺘﺨﺪﺍﻡ ﺍﻟﺒﺎﱐ ﺍﳉﺪﻳﺪ ﺇﻟﺰﺍﻣﻴﺎ ‪ ،‬ﻭﻟﻠﺘﻐﻠﺐ ﻋﻠﻰ ﻫﺬﺓ ﺍﳊﺎﻟﺔ ﻭﺇﺑﻘﺎﺀ ﺍﻟﺒﺎﱐ ﺍﻷﺳﺎﺳﻲ ﻣﺘﺎﺣﺎ ﺑﺎﻹﺿﺎﻓﺔ ﺇﱃ ﺍﻟﺒﺎﱐ ﺍﳉﺪﻳﺪ ﻋﻠﻴﻚ‬
‫ﺇﺳﺘﺨﺪﺍﻡ ﻣﻴﺰﺓ ﺍﻟﺘﺤﻤﻴﻞ ﺍﻟﺰﺍﺋﺪ ﻷﲰﺎﺀ ﺍﳌﻨﺎﻫﺞ ﻭﺍﻟﱵ ﺳﺒﻖ ﺫﻛﺮﻫﺎ ‪ .‬ﻣﺜﺎﻝ ‪:‬‬
‫‪type‬‬
‫‪TDate = class‬‬
‫‪public‬‬
‫;‪constructor Create; overload‬‬ ‫‪// the old constructor‬‬
‫;‪constructor Create (y, m, d: Integer); overload‬‬ ‫‪// the new constructor‬‬

‫ﺣﻴﺚ ﻧﺴﺘﻄﻴﻊ ﺿﺒﻂ ﻗﻴﻤﺔ ﺍﻟﺘﺎﺭﻳﺦ ﻋﻨﺪ ﺍﻹﻧﺸﺎﺀ ﰲ ﺍﳊﺎﻟﺔ ﺍﻟﺜﺎﻧﻴﺔ ‪ ،‬ﺃﻣﺎ ﺍﳊﺎﻟﺔ ﺍﻷﻭﱃ ﺳﺘﺄﺧﺬ ﻗﻴﻤﺔ ﺍﻟﺘﺎﺭﻳﺦ ﺍﻹﻓﺘﺮﺍﺿﻲ )ﺃﻭ‬
‫ﺍﳊﺎﱄ ﻣﺜﻼ ( ‪.‬‬

‫‪٢٤‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﲡﺮﺑﺔ ‪:‬‬

‫ﺇﺫﺍ ﱂ ﻧﺴﺘﺨﺪﻡ ﺍﻟﺘﺤﻤﻴﻞ ﺍﻟﺰﺍﺋﺪ ﻓﺈﻥ ﺍﻟﺒﺎﱐ ﺍﳉﺪﻳﺪ ﺳﻴﺤﻞ ﲤﺎﻣﺎ ﳏﻞ ﺍﻟﺒﺎﱐ ﺍﻟﻘﺪﱘ ‪ ،‬ﻭﻟﻦ ﻳﺼﺒﺢ ﺑﺎﻹﻣﻜﺎﻥ ﺇﺳﺘﺨﺪﺍﻡ ﺍﻟﺒﺎﱐ ﺍﻟﻘﺪﱘ‬
‫‪ ،‬ﻣﺜﻼ ﺟﺮﺏ ﺍﻟﺸﻔﺮﺓ ﺍﻟﺘﺎﻟﻴﺔ ﻭﻻﺣﻆ ﺍﳋﻄﺄ ﺍﻟﻨﺎﺗﺞ ﻋﻨﺪ ﳏﺎﻭﻟﺔ ﺇﺳﺘﺪﻋﺎﺀ ﺍﻟﺒﺎﱐ ﺍﻷﺻﻠﻲ ‪:‬‬
‫‪type‬‬
‫‪TDate = class‬‬
‫‪public‬‬
‫;)‪constructor Create (y, m, d: Integer‬‬

‫‪…..‬‬

‫‪var‬‬
‫;‪ADay: TDate‬‬
‫‪begin‬‬
‫‪// Error, does not compile:‬‬
‫;‪ADay := TDate.Create‬‬
‫‪// This one is OK:‬‬
‫;)‪ADay := TDate.Create (1, 1, 2000‬‬

‫ﻣﻼﺣﻈﺔ ﻣﻬﻤﺔ ‪ :‬ﺇﻥ ﻗﻮﺍﻋﺪ ﻛﺘﺎﺑﺔ ﺍﻟﺒﺎﱐ ﻣﻦ ﺃﺟﻞ ﻋﻨﺎﺻﺮ ﺟﺪﻳﺪﺓ ﲣﺘﻠﻒ ﻗﻠﻴﻼ ﻛﻤﺎ ﺳﺘﻼﺣﻆ ﰲ ﺍﻟﻘﺴﻢ ﺍﳋﺎﺹ ﺑﺒﻨﺎﺀ ﻋﻨﺎﺻﺮ‬
‫ﺟﺪﻳﺪﺓ ‪ .‬ﺣﻴﺚ ﺳﺘﻼﺣﻆ ﺇﺳﺘﺨﺪﺍﻡ ﺍﻟﺒﺎﱐ ﺍﻟﻘﺪﱘ ﺿﻤﻦ ﺍﻟﺒﺎﱐ ﺍﳉﺪﻳﺪ ﺑﻌﻤﻠﻴﺔ " ‪. " override‬‬

‫ﺍﳍﺎﺩﻡ ‪ Destructor‬ﻭﺍﳌﻨﻬﺞ ‪: Free‬‬

‫ﺑﻨﻔﺲ ﺍﻟﻄﺮﻳﻘﺔ ‪ ،‬ﺑﺎﻹﺿﺎﻓﺔ ﺇﱃ ﺇﻣﻜﺎﻧﻴﺔ ﻛﺘﺎﺑﺔ ﺑﺎﱐ ﺧﺎﺹ ﻟﻠﺼﻨﻒ ‪ ،‬ﳝﻜﻦ ﻛﺬﻟﻚ ﻛﺘﺎﺑﺔ ﻫﺎﺩﻡ ﺧﺎﺹ ﻟﺔ ‪ .‬ﻭﻳﻘﻮﻡ ﺑﺎﻟﻌﻤﻞ‬
‫ﺍﳌﻌﺎﻛﺲ ﺣﻴﺚ ﳛﺮﺭ ﺃﻱ ﺫﺍﻛﺮﺓ ﻗﺎﻡ ﺍﻟﺒﺎﱐ ﲝﺠﺰﻫﺎ ﻭﱂ ﲢﺮﺭ ﻓﻴﻤﺎ ﺑﻌﺪ ‪ .‬ﻭﻳﺒﺪﺃ ﺑﺎﻟﻜﻠﻤﺔ ﺍﳌﻔﺘﺎﺣﻴﺔ ‪ destructor‬ﻭ ﻳﻜﻮﻥ ﺇﲰﺔ‬
‫‪. Destroy‬‬

‫ﺳﺘﺮﻯ ﻻﺣﻘﺎ ﺇﻣﻜﺎﻧﻴﺔ ﺇﺳﺘﺨﺪﺍﻡ ﺍﳍﺎﺩﻡ ﺍﻟﻘﺪﱘ ﺿﻤﻦ ﺍﳉﺪﻳﺪ ﻣﻦ ﺃﺟﻞ ﺃﻥ ﻳﻘﻮﻡ ﺍﻟﺼﻨﻒ ﺑﺒﻌﺾ ﻋﻤﻠﻴﺎﺕ ﺍﻟﺘﻨﻈﻴﻒ ﺩﻭﻥ ﺃﻥ‬
‫ﻧﺸﻐﻞ ﺑﺎﻟﻨﺎ ﻓﻴﻬﺎ ﻣﻦ ﺟﺪﻳﺪ ‪.‬‬

‫ﻻ ﺗﺴﺘﺨﺪﻡ ﺃﺑﺪﺍ ﺇﺳﻢ ﻟﻠﻬﺎﺩﻡ ﻏﲑ ﺍﻹﺳﻢ ‪ ، Destroy‬ﻹﻥ ﺍﻷﻏﺮﺍﺽ ﻳﺘﻢ ﲢﺮﻳﺮﻫﺎ ﻋﺎﺩﺓ ﺑﺎﳌﻨﻬﺞ ﺍﻟﺸﻬﲑ ‪ Free‬ﻭﻣﺒﺪﺃ ﻫﺬﺍ‬
‫ﺍﳌﻨﻬﺞ)‪ :(Free‬ﻫﻮ ﺇﺧﺘﺒﺎﺭ ﺇﺫﺍ ﻛﺎﻧﺖ ﻗﻴﻤﺔ ﺍﻟﻐﺮﺽ ‪ Nil‬ﻗﺒﻞ ﺃﻥ ﻳﺴﺘﺪﻋﻲ ﺍﳌﻨﻬﺞ ﺍﳍﺎﺩﻡ ‪ ، Destroy‬ﻭﺑﺎﻟﺘﺎﱄ ﻓﺈﻥ ‪ Free‬ﻟﻦ‬
‫ﻳﺘﻌﺮﻑ ﻋﻠﻰ ﺍﳍﺎﺩﻡ ﺍﳉﺪﻳﺪ ﺍﻟﺬﻱ ﻗﻤﻨﺎ ﺑﺒﻨﺎﺀﺓ ﺇﺫﺍ ﱂ ﻳﻜﻦ ﺇﲰﺔ ‪ Destroy‬ﻭﺳﺘﻨﺘﺞ ﺃﺧﻄﺎﺀ ‪.‬‬

‫ﺇﻥ ‪ Free‬ﻫﻲ ﻣﻨﻬﺞ ﻟﻠﺼﻨﻒ ﺍﻷﺏ ‪ Tobject‬ﻭﺍﻟﺬﻱ ﺗﺮﺛﺔ ﻛﻞ ﺍﻷﻏﺮﺍﺽ ﺍﻷﺧﺮﻯ ‪.‬‬

‫‪٢٥‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻭﺍﳉﺪﻳﺮ ﺑﺎﻟﺬﻛﺮ ﻫﻨﺎ ﺃﻥ ‪ Free‬ﻟﻦ ﺗﻘﻮﻡ ﺑﻀﺒﻂ ﻗﻴﻤﺔ ﺍﻟﻐﺮﺽ ﺇﱃ ‪ Nil‬ﺑﻌﺪ ﲢﺮﻳﺮ ﺍﻟﺬﺍﻛﺮﺓ ﺍﳋﺎﺻﺔ ﺑﻪ ‪.‬ﻟﺬﻟﻚ ﻋﻠﻴﻚ ﺃﻥ ﺗﻘﻮﻡ‬
‫ﺑﺬﻟﻚ ﺑﻨﻔﺴﻚ ﻭﺍﻟﺴﺒﺐ ﺑﺴﻴﻂ ﺃﻥ ﺍﻟﻐﺮﺽ ﻟﻦ ﻳﻌﺮﻑ ﻣﺎ ﻫﻲ ﺍﳌﺘﺤﻮﻻﺕ ﺍﻟﱵ ﻧﺴﺒﺖ ﺇﻟﻴﺔ ‪ ،‬ﻭﻟﻦ ﻳﺴﺘﻄﻴﻊ ﺍﻟﺘﺄﻛﺪ ﻣﻦ ﺃﻧﻪ ﺿﺒﻂ‬
‫ﻗﻴﻤﺔ ﲨﻴﻊ ﻫﺬﺓ ﺍﳌﺘﺤﻮﻻﺕ ﺇﱃ ‪ ، Nil‬ﻟﺬﻟﻚ ﺗﺮﻛﺖ ﺍﻟﻌﻤﻠﻴﺔ ﺇﱃ ﺍﳌﺴﺘﺨﺪﻡ ‪ ،‬ﻭﻟﻜﻦ ﺩﻟﻔﻲ ﲤﻠﻚ ﺑﻌﺾ ﺍﻟﺪﻭﺍﻝ ﺍﳌﺴﺎﻋﺪﺓ ﻫﻨﺎ‬
‫ﻣﺜﻞ ﺍﻟﺪﺍﻟﺔ ‪ FreeAndNil‬ﺍﻟﱵ ﻗﺪ ﺗﺴﺎﻋﺪ ﺃﺣﻴﺎﻧﺎ ‪ .‬ﺣﻴﺚ ﺃ‪‬ﺎ ﲢﺮﺭ ﺍﻟﻐﺮﺽ ﻭﺗﻠﻐﻲ ﺍﳌﺮﺟﻊ ﺍﻟﺬﻱ ﻳﺸﲑ ﺇﻟﻴﺔ )ﻳﺼﺒﺢ ﺍﳌﺆﺷﺮ‬
‫ﻣﻌﺮﻓﺎ ﻣﺜﻞ ﺃﻱ ﻣﺘﺤﻮﻝ ﻭﻟﻜﻨﺔ ﻻﻳﺸﲑ ﺇﱃ ﺃﻱ ﻗﻴﻤﺔ ﺑﺎﻟﺬﺍﻛﺮﺓ ( ‪ .‬ﻋﻠﻰ ﻛﻞ ﺣﺎﻝ ﺗﺴﺘﻄﻴﻊ ﺍﻟﻘﻴﺎﻡ ﺑﺬﻟﻚ ﻳﺪﻭﻳﺎ ﺑﺈﺳﺘﺨﺪﺍﻡ‬
‫ﺍﻟﺴﻄﺮﻳﻦ ﺍﻟﺘﺎﻟﻴﲔ ‪:‬‬
‫;‪Obj1.Free‬‬
‫;‪Obj1 := nil‬‬

‫ﳕﻮﺫﺝ ﻣﺮﺟﻌﻴـﺔ ﺃﻏﺮﺍﺽ ﺩﻟﻔﻲ ‪:‬‬

‫ﺇﻥ ﺗﻌﺮﻳﻒ ﻣﺘﻐﻴﲑ ﻣﻦ ﺻﻨﻒ ﻣﺎ ‪ ،‬ﰲ ﺑﻌﺾ ﺍﻟﻠﻐﺎﺕ ﺍﻟﻐﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ ﺍﻷﺧﺮﻯ‪ ،‬ﺳﻴﻨﺸﻲﺀ ﻣﻨﺘﺴﺨﺎ ﻣﻦ ﻫﺬﺍ ﺍﻟﺼﻨﻒ ﺗﻠﻘﺎﺋﻴﺎ ‪.‬‬
‫ﻭﻟﻜﻦ ﺩﻟﻔﻲ ﻣﺒﻨﻴﺔ ﻋﻠﻰ ﳕﻮﺫﺝ ﻣﺮﺟﻌﻴﺔ ﺍﻟﻐﺮﺽ ﺑﺪﻻ ﻣﻦ ﺫﻟﻚ ‪ ،‬ﻭﺍﻟﻔﻜﺮﺓ ﰲ ﺫﻟﻚ ﺃﻥ ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑ ﰲ ﺩﻟﻔﻲ ﻣﻦ ﳕﻂ ﺻﻨﻒ‬
‫ﻣﺎ ﻟﻦ ﳜﺰﻥ ﺍﻟﻐﺮﺽ ﺩﺍﺧﻠﺔ ‪ ،‬ﻭﻟﻜﻨﺔ ﳜﺰﻥ ﻣﺮﺟﻊ ﳌﻮﻗﻊ ﺍﻟﻐﺮﺽ ﰲ ﺍﻟﺬﺍﻛﺮﺓ ‪ ،‬ﺃﻱ ﻋﺒﺎﺭﺓ ﻋﻦ ﻣﺆﺷﺮ )‪ (Pointer‬ﻳﺸﲑ ﺇﱃ ﻣﻮﻗﻊ‬
‫ﺧﺎﺹ ﺑﺎﻟﺬﺍﻛﺮﺓ ﺣﻴﺚ ﻳﺘﻢ ﲣﺰﻳﻦ ﺟﺴﻢ ﺍﻟﻐﺮﺽ ﻫﻨﺎﻙ ‪ ،‬ﻭﻟﻴﺲ ﺿﻤﻦ ﺍﳌﺘﻐﲑ ﻧﻔﺴﺔ ‪ ،‬ﻭﺑﻨﺎﺀ ﻋﻠﻰ ﺫﻟﻚ ﻛﻤﺎ ﻻﺣﻈﺖ ﻣﻌﻲ ﰲ‬
‫ﺍﻟﺼﻔﺤﺎﺕ ﺍﻟﺴﺎﺑﻘﺔ ﺇﻥ ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑ ﻻﻳﻌﲏ ﺇﻧﺸﺎﺀ ﺍﻟﻐﺮﺽ ﰲ ﺍﻟﺬﺍﻛﺮﺓ )ﳑﺎ ﻳﺮﺑﻚ ﻣﺴﺘﺨﺪﻣﻲ ﺩﻟﻔﻲ ﺍﳉﺪﺩ( ‪ ،‬ﻭﻟﻜﻨﻚ ﺗﻜﻮﻥ‬
‫ﺣﺠﺰﺕ ﻣﻮﻗﻊ ﺫﺍﻛﺮﺓ ﺻﻐﲑ ﳛﻮﻱ ﻋﻨﻮﺍﻥ ﻣﻮﻗﻊ ﺍﻟﺬﺍﻛﺮﺓ ﺍﻵﺧﺮ ﺍﻟﺬﻱ ﳜﺰﻥ ﺍﻟﻐﺮﺽ ‪ . ،‬ﻭﺍﻷﺻﻨﺎﻑ ﺍﻟﱵ ﻧﻌﺮ‪‬ﻓﻬﺎ ﻳﺪﻭﻳﺎ ﲢﺘﺎﺝ‬
‫ﺇﱃ ﺇﻧﺸﺎﺀ ﻳﺪﻭﻱ )ﺍﳌﻨﻬﺞ ‪ ، (Create‬ﺃﻣﺎ ﺍﻟﻌﻨﺎﺻﺮ ﺍﻟﱵ ﺗﻀﻌﻬﺎ ﻋﻠﻰ ﺍﻟﺸﻜﻞ )‪ (Form‬ﺳﺘﻘﻮﻡ ﺩﻟﻔﻲ ﺑﺈﻧﺸﺎﺋﻬﺎ ﺁﻟﻴﺎ ‪.‬‬

‫ﻭﺑﺎﻟﻄﺒﻊ ﲢﺘﺎﺝ ﺇﱃ ﲢﺮﻳﺮ ﺍﻷﻏﺮﺍﺽ ﺍﻟﱵ ﺇﻧﺘﻬﻴﺖ ﻣﻦ ﺇﺳﺘﺨﺪﺍﻣﻬﺎ ‪ ،‬ﻹ‪‬ﺎ ﺃﺻﺒﺤﺖ ﺗﺸﻐﻞ ﺫﺍﻛﺮﺓ ﻏﲑ ﻣﻔﻴﺪﺓ ‪.‬‬

‫ﻃﺎﳌﺎ ﺗﻘﻮﻡ ﺑﺈﻧﺸﺎﺀ ﺍﻷﻏﺮﺍﺽ ﻭﲢﺮﻳﺮﻫﺎ ﻋﻨﺪ ﺍﻹﻧﺘﻬﺎﺀ ﻓﺈﻥ ﳕﻮﺫﺝ ﻣﺮﺟﻌﻴﺔ ﺍﻟﻐﺮﺽ ﻳﻌﻤﻞ ﺑﺪﻭﻥ ﺃﺩﱏ ﻣﺸﻜﻠﺔ ﻭﻳﻌﺘﱪ ﻣﺘﻤﺎﺳﻜﺎ‬
‫ﺟﺪﺍ ‪ ،‬ﺃﻣﺎ ﺍﳋﱪ ﺍﻟﺴﻌﻴﺪ ﺍﻵﻥ ﺃﻧﺔ ﳝﻠﻚ ﺃﳘﻴﺔ ﺧﺎﺻﺔ ﻭﻗﺪﺭﺓ ﻋﺎﻟﻴﺔ ﻋﻠﻰ ﺇﺩﺍﺭﺓ ﺍﻟﺬﺍﻛﺮﺓ ﻭﻟﺔ ﺍﻟﻜﺜﲑ ﻣﻦ ﺍﻟﻔﻮﺍﺋﺪ ‪ ،‬ﻭﺃﻟﻴﻚ ﺑﻌﻀـﺎﹰ‬
‫ﻣﻦ ﺫﻟﻚ ‪:‬‬

‫ﻧﺴﺐ ﺍﻷﻏﺮﺍﺽ ‪:‬‬

‫ﲟﺎ ﺃﻥ ﺍﳌﺘﻐﲑ ﺍﻟﺬﻱ ﳛﻮﻱ ﺍﻟﻐﺮﺽ ﻳﺪﻝ ﻓﻘﻂ ﻋﻠﻰ ﺍﻟﻌﻨﻮﺍﻥ ﺍﻷﺳﺎﺳﻲ ﻟﻠﻐﺮﺽ ﰲ ﺍﻟﺬﺍﻛﺮﺓ ‪ ،‬ﻓﺈﻧﻨﺎ ﻧﺴﺘﻄﻴﻊ ﺗﻌﺮﻳﻒ ﺃﻛﺜﺮ ﻣﻦ‬
‫ﻣﺘﺤﻮﻝ ﺗﺪﻝ ﲨﻴﻌﻬﺎ ﻋﻠﻰ ﺍﻟﻐﺮﺽ ﻧﻔﺴﻪ ‪ ،‬ﻓﺈﺫﺍ ﻗﻤﻨﺎ ﺑﻨﺴﺐ ﻣﺘﺤﻮﻝ ﺟﺪﻳﺪ ﻣﺎ ﻣﻦ ﻧﻔﺲ ﺍﻟﺼﻨﻒ ﺇﱃ ﺁﺧﺮ ﲤﺖ ‪‬ﻴﺌﺘﺔ ﻓﺈﻧﻨﺎ‬
‫ﻧﺴﺘﻄﻴﻊ ﺍﻟﺘﻌﺎﻣﻞ ﻣﻊ ﺍﳌﺘﺤﻮﻝ ﺍﳉﺪﻳﺪ ﺩﻭﻥ ﺃﺩﱏ ﻣﺸﻜﻠﺔ ‪.‬‬

‫‪٢٦‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻣﺜﺎﻝ ‪:‬‬
‫;)‪procedure Tform1.Button1Click(Sender: TObject‬‬
‫‪var‬‬
‫;‪NewDay: TDate‬‬
‫‪begin‬‬
‫;‪NewDay := TDate.Create‬‬
‫;‪TheDay := NewDay‬‬
‫;‪Label1.Caption := TheDay.GetText‬‬
‫;‪end‬‬

‫ﻣﺎﺫﺍ ﺣﺼﻞ ‪ ...‬؟ ﻳﻘﻮﻡ ﻫﺬﺍ ﺍﻟﻜﻮﺩ ﺑﻨﺴﺦ ﻣﻮﻗﻊ ﺫﺍﻛﺮﺓ ﺍﻟﻐﺮﺽ ﺍﻟﺬﻱ ﻳﺸﲑ ﺇﻟﻴﺔ ﺍﳌﺘﺤﻮﻝ ‪ NewDay‬ﻭﻭﺿﻌﺔ ﰲ ﺍﳌﺘﺤﻮﻝ‬
‫‪ ، TheDay‬ﺇﻥ ﺫﻟﻚ ﻟﻴﺲ ﻧﺴﺦ ﺑﻴﺎﻧﺎﺕ ﻏﺮﺽ ﻣﺎ ﺇﱃ ﻏﺮﺽ ﺁﺧﺮ ‪ ،‬ﺇﻥ ﻫﺬﺓ ﺍﻟﻌﻤﻠﻴﺔ ﺳﻬﻠﺔ ﻭﺳﺮﻳﻌﺔ ﺍﻟﺘﻨﻔﻴﺬ ﻹ‪‬ﺎ ﺗﻨﻘﻞ ﻋﻨﺎﻭﻳﻦ‬
‫ﻣﻮﺍﻗﻊ ﺍﻟﺬﺍﻛﺮﺓ ﻓﻘﻂ ‪.‬‬

‫ﻭﻟﻜﻦ ﻋﻠﻴﻚ ﺃﻥ ﲢﺬﺭ ﻣﻦ ﺫﻟﻚ ‪ ،‬ﻭﲢﺴﻦ ﺇﺳﺘﺨﺪﺍﻣﺔ ‪ ،‬ﻻﺣﻆ ﺃﻧﻨﺎ ﺳﻨﻘﻮﻡ ﺑﺈﻧﺸﺎﺀ ﺍﻟﻐﺮﺽ ﻣﻦ ﺟﺪﻳﺪ ﻛﻞ ﻣﺮﺓ ﻳﺘﻢ ﺍﻟﻀﻐﻂ‬
‫ﻋﻠﻰ ﺍﻟﺰﺭ ‪ button1‬ﻭﱂ ﻧﻘﻢ ﺑﺘﺤﺮﻳﺮﺓ ﺑﺈﺳﺘﺨﺪﺍﻡ ‪ Free‬ﻣﺜﻼ ‪،‬‬

‫ﻭﻟﺘﺠﻨﺐ ﺫﻟﻚ ﺗﺴﺘﻄﻴﻊ ﺑﺒﺴﺎﻃﺔ ﲢﺮﻳﺮ ﺍﻟﻐﺮﺽ ﺍﻟﻘﺪﱘ ﻗﺒﻞ ﺑﻨﺎﺀ ﺍﻟﻐﺮﺽ ﺍﳉﺪﻳﺪ ‪:‬‬
‫;)‪procedure TDateForm.BtnTodayClick(Sender: TObject‬‬
‫‪begin‬‬
‫;‪TheDay.Free‬‬
‫;‪TheDay := TDate.Create‬‬

‫ﺇﻥ ﻫﺬﺓ ﺍﳌﻴﺰﺓ ﺗﺒﺪﻭ ﻣﻴﺰﺓ ﻋﺎﺩﻳﺔ ﺑﺪﺍﻳﺔ ﻭﻟﻜﻦ ﻋﻠﻴﻚ ﺃﻥ ﺗﻌﺮﻑ ﺃﻥ ﳍﺎ ﺗﻄﺒﻴﻘﺎﺕ ﻣﻬﻤﺔ ‪ ،‬ﺇﻥ ﺇﻣﻜﺎﻧﻴﺔ ﺗﻌﺮﻳﻒ ﻣﺘﺤﻮﻝ ﺟﺪﻳﺪ‬
‫ﳝﻜﻨﺔ ﺃﻥ ﻳﺸﲑ ﺇﱃ ﻏﺮﺽ ﻣﺎ ﳚﻌﻞ ﻣﻦ ﺍﳌﻤﻜﻦ ﺇﺳﺘﺨﺪﺍﻡ ﺍﳌﺘﺤﻮﻝ ﻟﺘﺨﺰﻳﻦ ﺍﻟﻐﺮﺽ ﺍﻟﻨﺎﺗﺞ ﻣﻦ ﻗﺮﺍﺀﺓ ﺇﺣﺪﻯ ﺍﳋﺼﺎﺋﺺ ‪،‬‬
‫ﻭﺇﺳﺘﺨﺪﺍﻣﻪ ﻓﻴﻤﺎ ﺑﻌﺪ ‪ ،‬ﻣﺜﻼ ‪:‬‬
‫‪var‬‬
‫;‪ADay: TDate‬‬
‫‪begin‬‬
‫;‪ADay := UserInformation.GetBirthDate‬‬
‫‪// use a ADay‬‬

‫ﺇﻧﻨﺎ ﻧﻜﺴﺐ ﺩﻳﻨﺎﻣﻴﻜﻴﺔ ﺧﺎﺻﺔ ﻟﻠﺘﻌﺎﻣﻞ ﻣﻊ ﺍﻷﻏﺮﺍﺽ ﻭﻧﺴﺘﻄﻴﻊ ﺗﺸﺒﻴﺔ ﺫﻟﻚ ﺑﺄﻱ ﻣﺘﺤﻮﻝ ﻋﺎﺩﻱ ‪.‬‬

‫ﻛﻤﺎ ﺗﺴﺘﻄﻴﻊ ﲤﺮﻳﺮ ﺍﻟﻐﺮﺽ ‪‬ﺬﺓ ﺍﻟﻄﺮﻳﻘﺔ ﻋﻠﻰ ﺷﻜﻞ ﺑﺎﺭﺍﻣﺘﺮ ﺧﺎﺹ ﺑﺘﺎﺑﻊ ﻣﺎ ‪ ،‬ﺃﻱ ﺃﻧﻨﺎ ﻧﻌﺎﻣﻞ ﺍﻟﻐﺮﺽ ﻛﻤﺘﺤﻮﻝ ﻭﳕﺮﺭﺓ ﺇﱃ‬
‫ﻣﻨﺎﻫﺞ ﺗﻘﻮﻡ ﲟﻌﺎﳉﺘﺔ ﻭﺍﻟﺘﻌﺪﻳﻞ ﻓﻴﺔ ﻣﻦ ﻣﻜﺎﻧﺔ ‪.‬‬

‫ﻣﺜﻼ ﻧﻔﺮﺽ ﺇﺟﺮﺍﺋﻴﺔ ﳍﺎ ﺑﺎﺭﺍﻣﺘﺮ ﻭﺣﻴﺪ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ ، TButton‬ﳕﺮﺭ ﳍﺎ ﺯﺭ ﻣﺎ ﻓﺘﻘﻮﻡ ﺑﺘﻐﻴﲑ ﺇﲰﺔ ﻣﺜﻼ ﺃﻭ ﺃﻱ ﺑﻴﺎﻧﺎﺕ ﳝﻠﻜﻬﺎ ‪:‬‬
‫;)‪procedure ChangeCaption (B: TButton‬‬
‫‪begin‬‬
‫;'‪B.Caption := B.Caption + ' was Modified‬‬
‫;‪end‬‬
‫…………‬
‫‪// call...‬‬
‫)‪ChangeCaption (Button1‬‬

‫‪٢٧‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﳌﺘﺤﻮﻝ ﺍﻟﺬﻱ ﻗﻤﻨﺎ ﺑﺘﻤﺮﻳﺮﺓ ﻛﺰﺭ ﺃﻋﻄﻰ ﻋﻨﻮﺍﻥ ﺍﻟﺬﺍﻛﺮﺓ ﻟﻺﺟﺮﺍﺋﻴﺔ ﺍﻟﱵ ﺩﺧﻠﺖ ﺇﻟﻴﺔ ﻭﻗﺎﻣﺖ ﺑﺎﻟﺘﻌﺎﻣﻞ ﻣﻌﻪ ﻣﺒﺎﺷﺮﺓ ‪.،‬‬

‫ﻫﺬﺍ ﻳﻌﲏ ﺃﻥ ﺍﻟﻐﺮﺽ ﰎ ﲤﺮﻳﺮﺓ ﺑﺎﳌﺮﺟﻊ ﺑﻼ ﺇﺳﺘﺨﺪﺍﻡ ﺍﻟﻜﻠﻤﺔ ﺍﳌﻔﺘﺎﺣﻴﺔ ‪ Var‬ﺍﻟﱵ ﻧﺴﺘﺨﺪﻣﻬﺎ ﺑﺎﳊﺎﻟﺔ ﺍﻟﻌﺎﺩﻳﺔ‪ ،‬ﻭﺑﺪﻭﻥ ﺃﻱ ﻣﻦ‬
‫ﺍﻟﺘﻘﻴﻴﺪﺍﺕ ﺍﻷﺧﺮﻯ ﺍﻟﱵ ﺗﻔﺮﺿﻬﺎ ﺣﺎﻟﺔ ﺍﻟﺘﻤﺮﻳﺮ ﺑﺎﳌﺮﺟﻊ )‪. (pass-by-reference‬‬

‫ﻟﻜﻦ ﻣﺎﺫﺍ ﻟﻮﻛﻨﺎ ﻧﺮﻳﺪ ﺃﻥ ﻧﻘﻮﻡ ﺑﻨﺴﺦ ﺍﻟﺒﻴﺎﻧﺎﺕ ﻓﻌﻠﻴﺎ ﻣﻦ ﻏﺮﺽ ﺇﱃ ﺁﺧﺮ ‪ ،‬ﻫﺬﺓ ﺍﳌﺮﺓ ﻻﻧﺮﻳﺪ ﺍﻟﺘﻌﺎﻣﻞ ﻣﻊ ﻣﺘﻐﲑﺍﺕ ﻭﻋﻨﺎﻭﻳﻦ ‪،‬‬
‫ﻹﻧﻨﺎ ﻧﺮﻳﺪ ﻧﺴﺦ ﻓﻌﻠﻲ ﻟﻠﻐﺮﺽ ‪ .‬ﺭﲟﺎ ﻋﻠﻴﻨﺎ ﺃﻥ ﻧﻘﻮﻡ ﺑﻨﺴﺦ ﻛﻞ ﺣﻘﻞ ﻣﻦ ﺣﻘﻮﻝ ﺍﻟﻐﺮﺽ ‪ ،‬ﻭﻟﻜﻦ ﺭﲟﺎ ﻻﺗﻜﻮﻥ ﻛﻞ ﺍﳊﻘﻮﻝ‬
‫ﻣﻌﺮﻓﺔ ‪ Public‬ﺃﻱ ﻻﻧﺴﺘﻄﻴﻊ ﺍﻟﻮﺻﻮﻝ ﺇﻟﻴﻬﺎ ﲨﻴﻌﻬﺎ ‪. ،‬‬

‫ﰲ ﻫﺬﺓ ﺍﳊﺎﻟﺔ ﻧﺴﺘﺨﺪﻡ ﻣﻨﻬﺞ ﺧﺎﺹ ﻳﻘﻮﻡ ﺑﻨﺴﺦ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﻟﺪﺍﺧﻠﻴﺔ ﻛﻠﻬﺎ ‪ ،‬ﺃﺻﻨﺎﻑ ﻣﻜﺘﺒﺔ ﺍﻟﻌﻨﺎﺻﺮ ﺍﳌﺮﺋﻴﺔ ﰲ ﺩﻟﻔﻲ ﻭﺍﻟﱵ ﰎ‬
‫ﺗﻮﺭﻳﺜﻬﺎ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ Tpersistent‬ﲤﻠﻚ ﺍﳌﻨﻬﺞ ‪ Assign‬ﻭﺍﻟﺬﻱ ﻳﻘﻮﻡ ‪‬ﺬﺓ ﺍﻟﻌﻤﻠﻴﺔ ‪.‬‬

‫)ﻣﻼﺣﻈﺔ ﻫﺬﺍ ﺍﳌﻨﻬﺞ ﻏﲑ ﻣﺘﻮﻓﺮ ﰲ ﲨﻴﻊ ﺃﺻﻨﺎﻑ ﺍﻟـ ‪ VCL‬ﺣﱴ ﺍﳌﻮﺭﺛﺔ ﻣﻦ ‪ Tpersistent‬ﺃﺣﻴﺎﻧﺎ ( ‪.‬‬

‫ﻣﻼﺣﻈﺔ ‪ :‬ﻧﺴﺘﻄﻴﻊ ﺗﺰﻭﻳﺪ ﺍﻷﺻﻨﺎﻑ ﺍﻟﱵ ﻧﻘﻮﻡ ﺑﻜﺘﺎﺑﺘﻬﺎ ﲟﻨﺎﻫﺞ ﺷﺒﻴﻬﻪ ﺑﺎﳌﻨﻬﺞ ‪ Assign‬ﺑﺴﻬﻮﻟﺔ ﻣﻦ ﺩﺍﺧﻞ ﺷﻔﺮﺓ ﺍﻟﺼﻨﻒ‬
‫ﻹﻧﻨﺎ ﻧﺴﺘﻄﻴﻊ ﺍﻟﻮﻟﻮﺝ ﺇﱃ ﲨﻴﻊ ﺑﻴﺎﻧﺎﺕ ﺍﻟﺼﻨﻒ ﻣﺜﻼ ﻹﺿﺎﻓﺔ ﺍﳌﻨﻬﺞ ‪ Assign‬ﺇﱃ ﺍﻟﺼﻨﻒ ‪ Tdate‬ﺍﻟﺬﻱ ﻗﻤﻨﺎ ﺑﺒﻨﺎﺀﺓ ﺳﺎﺑﻘﺎ ‪:‬‬
‫;)‪procedure TDate.Assign (Source: TDate‬‬
‫‪begin‬‬
‫;‪fDate := Source.fDate‬‬
‫;‪end‬‬

‫)ﻻﺣﻆ ﺃﻥ ﺍﳌﺘﺤﻮﻝ ‪ fDate‬ﺍﻟﺬﻱ ﲣﺰﻥ ﺿﻤﻨﺔ ﻗﻴﻤﺔ ﺍﻟﺘﺎﺭﻳﺦ ﻻﻳﻜﻮﻥ ﻣﺘﺎﺣﺎ ﺧﺎﺭﺝ ﺍﻟﻮﺣﺪﺓ ﻹﻧﺔ ﻣﻌﺮﻑ ‪( private‬‬

‫ﻭﺳﻴﻜﻮﻥ ﺇﺳﺘﺨﺪﺍﻣﺔ ﺑﺎﻟﻄﺮﻳﻘﺔ ﺍﻟﺘﺎﻟﻴﺔ ﻣﺜﻼ ‪:‬‬


‫;)‪procedure TDateForm.BtnTodayClick(Sender: TObject‬‬
‫‪var‬‬
‫;‪NewDay: TDate‬‬
‫‪begin‬‬
‫;‪NewDay := TDate.Create‬‬
‫;)‪TheDay.Assign(NewDay‬‬
‫;‪LabelDate.Caption := TheDay.GetText‬‬
‫;‪NewDay.Free‬‬
‫;‪end‬‬

‫‪٢٨‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﻷﻏﺮﺍﺽ ﻭﺍﻟﺬﺍﻛﺮﺓ ‪:‬‬

‫ﺗﻮﺟﺪ ﺛﻼﺙ ﻗﻮﺍﻋﺪ ﻹﺩﺍﺭﺓ ﺍﻟﺬﺍﻛﺮﺓ ﰲ ﺩﻟﻔﻲ ‪ ،‬ﻋﻠﻰ ﺍﻷﻗﻞ ﻟﺘﻜﻮﻥ ﻭﺍﺛﻘﺎ ﺃﻥ ﺍﻟﻨﻈﺎﻡ ﻳﻌﻤﻞ ﺑﺘﻨﺎﻏﻢ ﻣﻦ ﺩﻭﻥ ﻇﻬﻮﺭ ﺭﺳﺎﺋﻞ‬
‫ﺇﻧﺘﻬﺎﻙ ﺍﻟﺬﺍﻛﺮﺓ ‪ ،‬ﺃﻭ ﻣﻦ ﺩﻭﻥ ﺗﺮﻙ ﻣﺴﺎﺣﺎﺕ ﻏﲑ ﻣﺴﺘﺨﺪﻣﺔ ﳏﺠﻮﺯﺓ ﺩﻭﻥ ﲢﺮﻳﺮﻫﺎ ‪.‬‬

‫• ﻛﻞ ﻏﺮﺽ ﳚﺐ ﺃﻥ ﻳﺘﻢ ﺇﻧﺸﺎﺀﺓ ﻗﺒﻞ ﺃﻥ ﻳﺘﻢ ﺇﺳﺘﺨﺪﺍﻣﺔ ‪.‬‬

‫• ﻛﻞ ﻏﺮﺽ ﳚﺐ ﺃﻥ ﻳﺘﻢ ﲢﺮﻳﺮﺓ ﺑﻌﺪ ﺍﻹﻧﺘﻬﺎﺀ ﻣﻦ ﺇﺳﺘﺨﺪﺍﻣﺔ‪.‬‬

‫• ﻛﻞ ﻏﺮﺽ ﳚﺐ ﺃﻥ ﻳﺘﻢ ﲢﺮﻳﺮﺓ ﻣﺮﺓ ﻭﺍﺣﺪﺓ ﻓﻘﻂ ‪.‬‬

‫ﺇﺫﺍ ﻛﻨﺖ ﺳﺘﻘﻮﻡ ﺑﺬﻟﻚ ﻳﺪﻭﻳﺎ ﺿﻤﻦ ﺷﻔﺮﺗﻚ ﺃﻭ ﺳﺘﺘﺮﻙ ﺩﻟﻔﻲ ﺗﻘﻮﻡ ﺑﺬﻟﻚ ﻋﻮﺿﺎ ﻋﻨﻚ ‪ ،‬ﻓﺈﻥ ﺫﻟﻚ ﻳﻌﺘﻤﺪ ﻋﻠﻰ ﺍﻟﻨﻤﻮﺫﺝ‬
‫ﺍﻟﺬﻱ ﺳﻮﻑ ﺗﻌﺘﻤﺪﺓ ﻣﻦ ﺑﲔ ﳕﺎﺫﺝ ﺇﺩﺍﺭﺓ ﺍﻟﺬﺍﻛﺮﺓ ﺍﻟﱵ ﺗﻘﺪﻣﻬﺎ ﺩﻟﻔﻲ ‪.‬‬

‫ﺗﺪﻋﻢ ﺩﻟﻔﻲ ﺛﻼﺙ ﺃﻧﻮﺍﻉ ﻣﻦ ﺇﺩﺍﺭﺓ ﺍﻟﺬﺍﻛﺮﺓ ﻟﻠﻌﻨﺎﺻﺮ ﺍﻟﺪﻳﻨﺎﻣﻴﻜﻴﺔ ‪:‬‬

‫ﻛﻠﻤﺎ ﻗﻤﺖ ﺑﺈﻧﺸﺎﺀ ﻏﺮﺽ ﻳﺪﻭﻳﺎ ﺿﻤﻦ ﺷﻔﺮﺗﻚ ‪ ،‬ﻋﻠﻴﻚ ﲢﺮﻳﺮﺓ ﻳﺪﻭﻳﺎ ﺃﻳﻀﺎ ‪ ،‬ﻭﺇﺫﺍ ﱂ ﺗﻘﻢ ﺑﺬﻟﻚ ﻓﺈﻥ ﺍﻟﺬﺍﻛﺮﺓ ﺍﻟﱵ‬ ‫•‬
‫ﻳﺴﺘﺨﺪﻣﻬﺎ ﻟﻦ ﲢﺮﺭ ﻛﻲ ﺗﺴﺘﻔﻴﺪ ﻣﻨﻬﺎ ﺑﻘﻴﺔ ﻋﻨﺎﺻﺮ ﺗﻄﺒﻴﻘﻚ ﺣﱴ ﻳﺘﻢ ﺇ‪‬ﺎﺀ ﺗﻨﻔﻴﺬ ﺍﻟﱪﻧﺎﻣﺞ ‪.‬‬

‫ﺗﺴﺘﻄﻴﻊ ﲢﺪﻳﺪ ﻋﻨﺼﺮ ﻣﺎﻟﻚ )‪ (owner component‬ﻟﻠﻌﻨﺎﺻﺮ ﺍﻟﱵ ﺗﻘﻮﻡ ﺑﺈﻧﺸﺎﺀﻫﺎ ‪ ،‬ﺑﺘﻤﺮﻳﺮ ﺍﳌﺎﻟﻚ ﺇﱃ ﺑﺎﱐ ﺍﻟﻌﻨﺼﺮ‬ ‫•‬

‫ﺍﳉﺪﻳﺪ ‪ .‬ﻭﻳﺼﺒﺢ ﺍﳌﺎﻟﻚ ﻣﺴﺆﻭﻻ ﻋﻦ ﲢﺮﻳﺮ ﺫﺍﻛﺮﺓ ﻛﻞ ﺍﻟﻌﻨﺎﺻﺮ ﺍﻟﱵ ﳝﻠﻜﻬﺎ ‪ ،‬ﺑﻌﺒﺎﺭﺓ ﺃﺧﺮﻯ ﻋﻨﺪ ﲢﺮﻳﺮ ﺷﻜﻞ‬
‫)‪ (Form‬ﻓﺈﻥ ﻛﻞ ﺍﻟﻌﻨﺎﺻﺮ ﺍﻟﱵ ﺗﺘﺒﻊ ﻟﺔ ﺳﻴﺘﻢ ﲢﺮﻳﺮﻫﺎ ﻣﻌﻪ ‪ .‬ﻭﺑﺎﻟﺘﺎﱄ ﰲ ﺣﺎﻟﺔ ﺍﻟﻌﻨﺎﺻﺮ )‪ (Components‬ﻋﻨﺪﻣﺎ‬
‫ﺗﻘﻮﻡ ﺑﺘﺤﺪﻳﺪ ﻋﻨﺼﺮ ﻣﺎﻟﻚ ﻟﻌﻨﺼﺮﻙ ‪ ،‬ﻻﺩﺍﻋﻲ ﻟﺘﺬﻛﺮ ﲢﺮﻳﺮﺓ ﻣﻦ ﺍﻟﺬﺍﻛﺮﺓ‪ .‬ﻭﻫﺬﺍ ﻫﻮ ﺍﻟﺘﺼﺮﻑ ﺍﻟﻘﻴﺎﺳﻲ ﻟﻠﻌﻨﺎﺻﺮ‬
‫ﺍﻟﱵ ﻗﻤﻨﺎ ﺑﻮﺿﻌﻬﺎ ﻋﻠﻰ ﺍﻟﺸﻜﻞ ‪ Form‬ﰲ ﺯﻣﻦ ﺍﻟﺘﺼﻤﻴﻢ ‪ ،‬ﺣﱴ ﺍﻟﺸﻜﻞ ﻭﺍﻟﺬﻱ ﻳﻌﺘﱪ ﻣﺎﻟﻜﺎ ﳌﻌﻈﻢ ﻋﻨﺎﺻﺮ ﺍﻟﺘﻄﺒﻴﻖ‬
‫ﻳﻜﻮﻥ ﳑﻠﻮﻛﺎ ﻣﻦ ﻗﺒﻞ ﺃﻏﺮﺍﺽ ‪ Application‬ﻭﺍﻟﱵ ﲢﺮﺭ ﺁﻟﻴﺎ ﻋﻨﺪ ﺇ‪‬ﺎﺀ ﺍﻟﺘﻄﺒﻴﻖ ‪.‬‬

‫ﻋﻨﺪﻣﺎ ﺗﻘﻮﻡ ﻣﻜﺘﺒﺔ ‪ RTL‬ﺑﺘﺨﺼﻴﺺ ﺍﻟﺬﺍﻛﺮﺓ ﻣﻦ ﺃﺟﻞ ﺍﻟﺴﻼﺳﻞ ﻭﺍﳌﺼﻔﻮﻓﺎﺕ ﺍﻟﺪﻳﻨﺎﻣﻴﻜﻴﺔ ‪ ،‬ﻓﺈ‪‬ﺎ ﺳﺘﻘﻮﻡ ﺁﻟﻴﺎ‬ ‫•‬
‫ﺑﺘﺤﺮﻳﺮ ﺍﻟﺬﺍﻛﺮﺓ ﻋﻨﺪﻣﺎ ﳜﺮﺝ ﺍﳌﺮﺟﻊ ﻣﻦ ﳎﺎﻝ ﺍﻟﺮﺅﻳﺎ ‪ ،‬ﻟﻦ ﲢﺘﺎﺝ ﻟﺘﺤﺮﻳﺮ ﺳﻠﺴﻠﺔ ﳏﺮﻓﻴﺔ ‪ ،‬ﻋﻨﺪﻣﺎ ﺗﺼﺒﺢ ﻏﲑ ﻗﺎﻳﻠﺔ‬
‫ﻟﻠﻮﺻﻮﻝ ﺳﻴﺘﻢ ﲢﺮﻳﺮﻫﺎ ‪.‬‬

‫‪٢٩‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﲢﺮﻳﺮ ﺍﻷﻏﺮﺍﺽ ﻣﺮﺓ ﻭﺍﺣﺪﺓ ﻓﻘﻂ ‪:‬‬

‫ﺇﺫﺍ ﻗﻤﺖ ﺑﺈﺳﺘﺪﻋﺎﺀ ﺍﳌﻨﻬﺞ ‪ Free‬ﺃﻭ ﺍﳍﺎﺩﻡ ‪ Destroy‬ﺃﻛﺜﺮ ﻣﻦ ﻣﺮﺓ ‪ ،‬ﻓﺈﻥ ﺫﻟﻚ ﺳﻴﻮﻟﺪ ﺧﻄﺄ ﺑﻼ ﺷﻚ ‪ .‬ﻭﻟﻜﻦ ﺇﺫﺍ ﺿﺒﻄﺖ‬
‫ﻣﺘﺤﻮﻝ ﺍﻟﻐﺮﺽ ﺇﱃ ‪ Nil‬ﻓﺈﻧﻚ ﺗﺴﺘﻄﻴﻊ ﺇﺳﺘﺪﻋﺎﺀ ﺍﳌﻨﻬﺞ ‪ Free‬ﺃﻛﺜﺮ ﻣﻦ ﻣﺮﺓ ﺩﻭﻥ ﺃﺧﻄﺎﺀ ‪.‬‬

‫ﻣﻼﺣﻈﺔ ‪ :‬ﺭﲟﺎ ﺗﺘﺴﺎﺋﻞ ﳌﺎﺫﺍ ﺗﺴﺘﻄﻴﻊ ﺑﺈﻣﺎﻥ ﺃﻥ ﺗﺴﺘﺪﻋﻲ ‪ Free‬ﺇﺫﺍ ﻛﺎﻥ ﻣﺮﺟﻊ ﺍﻟﻐﺮﺽ ‪ ، NIL‬ﻭﻻﺗﺴﺘﻄﻴﻊ ﺇﺳﺘﺪﻋﺎﺀ‬
‫‪ . Destroy‬ﺍﻟﺴﺒﺐ ﺃﻥ ‪ Free‬ﻫﻲ ﻣﻨﻬﺞ ﻣﻌﺮﻑ ﻋﻠﻰ ﻣﻮﻗﻊ ﺫﺍﻛﺮﺓ ﻣﻌﻄﻰ ‪ .‬ﰲ ﺣﲔ ﺃﻥ ﺍﻹﺳﺘﺪﻋﺎﺀ ﺍﻹﻓﺘﺮﺍﺿﻲ ‪Destroy‬‬
‫ﻳﺘﻢ ﲢﺪﻳﺪﺓ ﰲ ﺯﻣﻦ ﺍﻟﺘﺸﻐﻴﻞ ﺑﺎﻟﻨﻈﺮ ﺇﱃ ﺻﻨﻒ ﺍﻟﻐﺮﺽ ‪ ،‬ﻭﻫﻲ ﺗﻌﻠﻴﻤﺔ ﺧﻄﲑﺓ ﺟﺪﺍ ﰲ ﺣﺎﻝ ﺃﺳﺘﺨﺪﻣﺖ ﻭﱂ ﻳﻜﻦ ﺍﻟﻐﺮﺽ‬
‫ﻣﻮﺟﻮﺩﺍ ‪.‬‬

‫ﻭﻟﺘﺠﻤﻴﻊ ﺍﻷﻣﻮﺭ ﺑﺸﻜﻞ ﺟﻴﺪ ‪ ،‬ﺇﻟﻴﻚ ﻫﺬﺓ ﺍﳋﻄﻮﻁ ﺍﻟﻌﺮﻳﻀﺔ ‪:‬‬

‫ﺩﺍﺋﻤﺎ ﺇﺳﺘﺨﺪﻡ ﺍﳌﻨﻬﺞ ‪ Free‬ﻟﺘﺤﺮﻳﺮ ﺍﻷﻏﺮﺍﺽ ﺑﺪﻻ ﻣﻦ ﺍﳍﺎﺩﻡ ‪. Destroy‬‬ ‫•‬

‫ﺇﺳﺘﺨﺪﻡ ﺍﻟﺪﺍﻟﺔ ‪ ، FreeAndNill‬ﺃﻭ ﺇﺿﺒﻂ ﻣﺮﺟﻊ ﺍﻟﻐﺮﺽ ﺇﱃ ‪ Nil‬ﺑﻌﺪ ﺇﺳﺘﺪﻋﺎﺀ ﺍﳌﻨﻬﺞ ‪. Free‬‬ ‫•‬

‫ﺗﺴﺘﻄﻴﻊ ﺇﺧﺘﺒﺎﺭ ﺇﺫﺍ ﻛﺎﻧﺖ ﻗﻴﻤﺔ ﻣﺮﺟﻊ ﻏﺮﺽ ﻣﺎ ‪ Nil‬ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﻟﺘﺎﺑﻊ ‪. Assigned‬‬

‫ﺍﻟﻌﺒﺎﺭﺗﺎﻥ ﺍﻟﺘﺎﻟﻴﺘﺎﻥ ﻣﺘﻜﺎﻓﺌﺘﺎﻥ ﰲ ﻣﻌﻈﻢ ﺍﳊﺎﻻﺕ ‪:‬‬


‫‪if Assigned (ADate) then ...‬‬
‫‪if ADate <> nil then ...‬‬

‫ﺗﺬﻛﺮ ﺃﻧﻪ ﺣﱴ ﻟﻮﻛﺎﻧﺖ ﺍﻟﻘﻴﻤﺔ ﻟﻴﺴﺖ ‪ Nil‬ﻓﻬﺬﺍ ﻻ ﻳﻌﲏ ﺃﻥ ﺍﳌﺆﺷﺮ ﺻﺎﱀ ﻟﻠﺘﻌﺎﻣﻞ ‪ .‬ﻣﺜﺎﻝ ﺇﻥ ﺇﺳﺘﺨﺪﺍﻡ ﺍﳌﻨﻬﺞ ‪ Free‬ﺳﻴﺤﺮﺭ‬
‫ﺍﻟﻐﺮﺽ ﻭﻟﻜﻨﺔ ﻟﻦ ﻳﻀﺒﻄﺔ ﺇﱃ ‪ Nil‬ﻭﺑﺎﻟﺘﺎﱄ ﺍﻟﺘﻌﻠﻴﻤﺔ ﺍﻟﺘﺎﻟﻴﺔ ﺳﺘﺴﺒﺐ ﺧﻄﺄ ‪.‬‬
‫;‪ToDestroy.Free‬‬
‫‪if ToDestroy <> nil then‬‬
‫;‪ToDestroy.DoSomething‬‬

‫‪٣٠‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﻟﻮﺭﺍﺛﺔ ﻣﻦ ﺃﳕﺎﻁ ﻣﻮﺟﻮﺩﺓ ‪:‬‬

‫ﻏﺎﻟﺒﺎ ﻣﺎ ﳓﺘﺎﺝ ﻟﺒﻨﺎﺀ ﳕﻮﺫﺝ ﳐﺘﻠﻒ ﻗﻠﻴﻼ ﻣﻦ ﺻﻨﻒ ﻣﻮﺟﻮﺩ ‪ ،‬ﺑﺪﻻ ﻣﻦ ﺑﻨﺎﺀ ﺻﻨﻒ ﺟﺪﻳﺪ ﻣﻦ ﺍﻟﺒﺪﺍﻳﺔ ‪ ،‬ﺭﲟﺎ ﳓﺘﺎﺝ ﺇﺿﺎﻓﺔ‬
‫ﻣﻨﺎﻫﺞ ﺟﺪﻳﺪﺓ ﺃﻭ ﺧﺼﺎﺋﺺ ﺃﻭ ﺗﻌﺪﻳﻞ ﺃﺧﺮﻯ ﻣﻮﺟﻮﺩﺓ ‪.‬‬

‫ﻧﺴﺘﻄﻴﻊ ﻓﻌﻞ ﺫﻟﻚ ﺑﻄﺮﻳﻘﺘﲔ ‪ ،‬ﻧﺴﺦ ﺍﻟﺸﻔﺮﺓ ﻣﻦ ﻫﻨﺎﻙ ﻭﻟﺼﻘﻬﺎ ﻫﻨﺎ ‪) .‬ﻳﺪﻝ ﻋﻠﻰ ﺿﻌﻒ ﺧﱪﺓ ﺑﺎﻟﱪﳎﺔ ﻣﺎﱂ ﺗﻮﺟﺪ ﻏﺎﻳﺔ ﻣﱪﺭﺓ‬
‫ﻟﻪ ( ‪ ،‬ﻭﺑﺬﻟﻚ ﺳﺘﻀﺎﻋﻒ ﺷﻔﺮﺗﻚ ﻣﺮﺗﲔ ‪ ،‬ﻧﺎﻫﻴﻚ ﻋﻦ ﺍﻷﺧﻄﺎﺀ ‪ ،‬ﻭﺍﻟﻐﺮﻕ ﰲ ﺗﻔﺼﻴﻼﺕ ﺗﺒﻌﺪﻙ ﻋﻦ ﻣﺸﺮﻭﻋﻚ ﺍﻷﺳﺎﺳﻲ‬
‫ﺑﺒﺴﺎﻃﺔ ‪ ،‬ﻻ ﺗﻜﻦ ﻣﻦ ﺍﻟﺬﻳﻦ ﻳﺘﺒﻌﻮﻥ ﻫﺬﺍ ﺍﻟﻨﻮﻉ ﻣﻦ ﺍﳊﻠﻮﻝ ﻛﺤﻠﻮﻝ ﺃﺳﺎﺳﻴﺔ ‪ .‬ﳌﺎﺫﺍ ﻻ ﺗﻘﻮﻡ ﺑﺪﻻ ﻣﻦ ﺫﻟﻚ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺇﺣﺪﻯ‬
‫ﺃﺭﻭﻉ ﻣﻴﺰﺍﺕ ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴﺔ ‪ :‬ﺃﻻ ﻭﻫﻲ ﺍﻟﻮﺭﺍﺛـــﺔ )‪. (inheritance‬‬

‫ﻭﺭﺍﺛﺔ ﺻﻨﻒ ﻣﻮﺟﻮﺩ ﻋﻤﻠﻴﺔ ﺳﻬﻠﺔ ﺍﻟﺘﺤﻘﻴﻖ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺩﻟﻔﻲ ‪ ،‬ﻋﻠﻴﻚ ﻓﻘﻂ ﺃﻥ ﺗﺬﻛﺮ ﺇﺳﻢ ﺍﻟﺼﻨﻒ ﺍﳌﻮﺭﻭﺙ ﰲ ﺗﺮﻭﻳﺴﺔ‬
‫ﺗﻌﺮﻳﻒ ﺍﻟﺼﻨﻒ ﺍﳉﺪﻳﺪ ‪ .‬ﻻﺣﻆ ﺃﻥ ﺷﻔﺮﺓ ﻣﺸﺮﻭﻉ ﺟﺪﻳﺪ ﰲ ﺩﻟﻔﻲ ﲢﻮﻱ ﺍﻟﺘﻌﺮﻳﻒ ﺍﻟﺘﺎﱄ ‪:‬‬
‫‪type‬‬
‫)‪TForm1 = class(TForm‬‬
‫;‪end‬‬

‫ﻫﺬﺓ ﻫﻲ ﺍﻟﻮﺭﺍﺛﺔ ﻳﺎﺻﺪﻳﻘﻲ ‪ ،‬ﺍﻟﺘﻌﺮﻳﻒ ﺍﻟﺴﺎﺑﻖ ﻳﺪﻝ ﻋﻠﻰ ﺃﻥ ‪ Tform1‬ﻳﺮﺙ ﻛﻞ ﺻﻔﺎﺕ ﺍﻟﺼﻨﻒ ‪، Tform‬ﺍﳊﻘﻮﻝ ‪ ،‬ﺍﳌﻨﺎﻫﺞ‬
‫‪ ،‬ﺍﻷﺣﺪﺍﺙ ‪ ..‬ﻛﻞ ﺷﻲﺀ ‪ ،‬ﺗﺴﺘﻄﻴﻊ ﺃﻥ ﺗﺴﺘﺪﻋﻲ ﺃﻱ ﻣﻨﻬﺞ ﻋﺎﻡ ‪ Public‬ﻣﻌﺮﻑ ﰲ ﺍﻟﺼﻨﻒ ‪ Tform‬ﻣﻦ ﻏﺮﺽ ﻣﻦ ﺍﻟﺼﻨﻒ‬
‫ﺍﻟﻮﺍﺭﺙ ‪ ، Tform1‬ﻭﺍﻟﺬﻱ ﺑﺪﻭﺭﺓ ﻭﺭﺙ ﺑﻌﺾ ﺍﻟﺼﻔﺎﺕ ﻣﻦ ﺻﻨﻒ ﺃﺏ ﻟﻪ ﺣﱴ ﻧﺼﻞ ﺇﱃ ﺍﻟﺼﻨﻒ ﺍﻟﺴﻠﻒ ‪. Tobject‬‬

‫ﺑﺈﻣﻜﺎﻧﻚ ﺇﺿﺎﻓﺔ ﺑﻴﺎﻧﺎﺗﻚ ﺍﳋﺎﺻﺔ ﻟﻠﺼﻨﻒ ﺍﳉﺪﻳﺪ ‪ ،‬ﺃﻭ ﺗﻌﺪﻳﻞ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﳌﻮﺭﻭﺛﺔ ﻣﻦ ﺍﻟﺼﻨﻒ ﺍﻷﺏ ﺑﺈﻋﺎﺩﺓ ﺗﻌﺮﻳﻔﻬﺎ ﻟﻜﻦ ﰲ‬
‫ﻧﻔﺲ ﺍﻟﻮﺣﺪﺓ ‪.‬‬

‫ﻣﺜﻼ ﺇﺫﺍ ﺃﺭﺩﻧﺎ ﺃﻥ ﻧﺒﲏ ﺻﻨﻒ ﺟﺪﻳﺪ ﻣﺸﺘﻖ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ Tdate‬ﺍﻟﺬﻱ ﺳﺒﻖ ﻭﺑﻨﻴﻨﺎﻩ ‪ ،‬ﻭﻧﻌﺪﻝ ﰲ ﺍﳌﻨﻬﺞ ‪ GetText‬ﺍﳋﺎﺹ ﺑﺔ‬
‫‪type‬‬
‫)‪TNewDate = class (TDate‬‬
‫‪public‬‬
‫;‪function GetText: string‬‬
‫;‪end‬‬

‫…‬
‫;‪function TNewDate.GetText: string‬‬
‫‪begin‬‬
‫;)‪GetText := FormatDateTime ('dddddd', fDate‬‬
‫;‪end‬‬

‫ﻳﻜﻔﻲ ﺇﻋﺎﺩﺓ ﺗﻌﺮﻳﻒ ﺍﳌﻨﺎﻫﺞ ﺍﳌﻮﺟﻮﺩﺓ ﺑﻨﻔﺲ ﺍﻹﺳﻢ ﺣﱴ ﳓﺼﻞ ﻋﻠﻰ ﻧﺴﺨﺘﻨﺎ ﺍﳋﺎﺻﺔ ﻣﻨﻬﺎ‪ ،‬ﻫﺬ ﺍﻟﻌﻤﻞ ﻳﻮﻓﺮ ﺍﳉﻬﺪ ﻭﺍﻟﺘﻌﺐ ‪،‬‬
‫ﻭﺳﺘﻘﻮﻡ ﺩﻟﻔﻲ ﺑﺈﺳﺘﺒﺪﺍﻝ ﺍﻟﺘﻌﺮﻳﻒ ﺍﻟﻘﺪﱘ ﺑﺎﳉﺪﻳﺪ ﻭﺳﻴﺴﺘﺨﺪﻡ ﰲ ﻛﻞ ﻣﺮﺓ ﻳﺘﻢ ﺇﺳﺘﺪﻋﺎﺀﺓ ﻓﻴﻬﺎ ‪.‬‬

‫‪٣١‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫‪GetText‬‬ ‫ﻣﻼﺣﻈﺔ ‪ :‬ﰲ ﺍﳌﺜﺎﻝ ﺍﻟﺴﺎﺑﻖ ﻧﻀﻊ ﺗﻌﺮﻳﻒ ‪ TnewDate‬ﺿﻤﻦ ﻧﻔﺲ ﺍﻟﻮﺣﺪﺓ ﺍﻟﱵ ﻋﺮﻓﻨﺎ ‪‬ﺎ ‪ Tdate‬ﻹﻥ ﺍﳌﻨﻬﺞ‬
‫ﻳﺴﺘﺨﺪﻡ ﺍﳌﺘﺤﻮﻝ ﺍﳋﺎﺹ‪ fDate‬ﺍﳌﻌﺮﻑ ﻛـ ‪ Private‬ﺿﻤﻦ ‪ Tdate‬ﻭﻻﳝﻜﻦ ﺍﻟﻮﺻﻮﻝ ﺇﻟﻴﺔ ﻣﻦ ﺧﺎﺭﺝ ﺍﻟﻮﺣﺪﺓ ‪.‬‬

‫ﻭﻟﺘﻮﺿﻴﺢ ﺫﻟﻚ ﺃﻛﺜﺮ ﺩﻋﻨﺎ ﻧﻨﺘﻘﻞ ﻟﻠﻔﻘﺮﺓ ﺍﻟﺘﺎﻟﻴﺔ ‪:‬‬

‫ﺍﻟﺘﻐﻠﻴﻒ ﻭﺍﳊﻘﻮﻝ ﺍﶈﻤﻴﺔ ‪: Protected Fields and Encapsulation‬‬

‫ﻛﻤﺎ ﻻﺣﻈﺖ ﺃﻥ ﺷﻔﺮﺓ ﺍﳌﻨﻬﺞ ‪ GetText‬ﺍﳋﺎﺻﺔ ﺑﺎﻟﺼﻨﻒ ‪ TnewDate‬ﺳﺘﺘﺮﺟﻢ ﺑﻼ ﺃﺧﻄﺎﺀ ﻓﻘﻂ ﺇﻥ ﲤﺖ ﺇﺿﺎﻓﺘﻬﺎ ﰲ ﻧﻔﺲ‬
‫ﻭﺣﺪﺓ ﺍﻟﺼﻨﻒ ﺍﻷﺳﺎﺱ ‪ . Tdate‬ﻹ‪‬ﺎ ﻛﻤﺎ ﻭﺿﺤﻨﺎ ﲢﺎﻭﻝ ﺩﺧﻮﻝ ﺍﳌﺘﺤﻮﻝ ‪ fDate‬ﻭﺍﻟﺬﻱ ﻫﻮ ﻣﺘﺤﻮﻝ ﻣﻮﺿﻌﻲ ‪، Private‬‬

‫ﺇﺫﺍ ﺃﺭﺩﻧﺎ ﺃﻥ ﻧﻀﻊ ﺍﻟﺼﻨﻒ ﺍﳌﺸﺘﻖ ﰲ ﻭﺣﺪﺓ ﺟﺪﻳﺪﺓ ﺑﺪﻭﻥ ﺃﻥ ﳒﻌﻞ ﺍﳌﺘﺤﻮﻝ ‪ fDate‬ﻣﺘﺤﻮﻝ ﻋﺎﻡ ‪ Public‬ﳝﻜﻦ ﺍﻟﻮﺻﻮﻝ ﺇﻟﻴﺔ‬
‫ﻣﻦ ﺃﻱ ﻣﻜﺎﻥ ‪ ،‬ﻓﺈﻧﻨﺎ ﺳﻨﺠﺪ ﻃﺮﻳﻘﺘﲔ ﲢﻘﻘﺎﻥ ﺫﻟﻚ‬

‫‪ -‬ﺗﻌﺮﻳﻒ ﺍﳌﺘﺤﻮﻝ ‪ fDate‬ﻛﻤﺘﺤﻮﻝ ﳏﻤﻲ ﺃﻱ )‪ (Protected‬ﺑﺪﻻ ﻣﻦ ﺍﳌﺘﺤﻮﻝ ﺍﻟﻌﺎﻡ ﺃﻭ ﺍﶈﻠﻲ ‪ ،‬ﺇﺫﺍ ﻛﻨﺖ ﺗﺘﺬﻛﺮ ﺇﻥ‬
‫ﻫﺬﺍ ﺍﻟﻨﻮﻉ ﻳﺴﻤﺢ ﻓﻘﻂ ﻟﻸﺻﻨﺎﻑ ﺍﳌﺸﺘﻘﺔ ﻣﻦ ﺍﻟﺼﻨﻒ ﺍﻷﺳﺎﺳﻲ ﺑﺎﻟﺪﺧﻮﻝ ﻟﻠﺒﻴﺎﻧﺎﺕ ‪.‬‬

‫‪ -‬ﺗﺮﻙ ﺍﳌﺘﺤﻮﻝ ‪ Private‬ﻭﺇﺿﺎﻓﺔ ﻣﻨﻬﺞ ﳏﻤﻲ ‪ Protected‬ﻳﺆﻣﻦ ﺍﻟﻮﺻﻮﻝ ﻟﺔ ‪.‬‬

‫ﺭﲟﺎ ﻻﺣﻈﺖ ﻣﻌﻲ ﺃﻥ ﺍﻟﻄﺮﻳﻘﺔ ﺍﻷﻭﱃ ﻫﻲ ﺍﻷﻓﻀﻞ ﻹ‪‬ﺎ ﺃﻛﺜﺮ ﻋﻤﻮﻣﻴﺔ ﻋﻨﺪﻣﺎ ﻧﻮﺭﺙ ﺍﻟﺼﻨﻒ ﻟﻌﺪﺩ ﻛﺒﲑ ﻣﻦ ﺍﻷﺻﻨﺎﻑ‬
‫ﺍﻟﻔﺮﻋﻴﺔ ‪ ،‬ﻭﺃﻧﺼﺤﻚ ﺑﺈﺗﺒﺎﻋﻬﺎ ﺩﺍﺋﻤﺎ ‪ ،‬ﺣﱴ ﻟﻮ ﱂ ﲡﺪ ﺣﺎﺟﺔ ﺣﺎﻟﻴﺎ ﻟﺘﻌﺮﻳﻒ ﻣﻌﻄﻴﺎﺕ ﳏﻤﻴﺔ ﻗﻢ ﺑﺬﻟﻚ ﻣﻦ ﺃﺟﻞ ﺗﻮﺭﻳﺚ‬
‫ﺃﺻﻨﺎﻑ ﺟﺪﻳﺪﺓ ﻣﺴﺘﻘﺒﻼ ‪ ،‬ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﶈﻤﻴﺔ ﲡﻌﻞ ﺍﻟﺼﻨﻒ ﻗﺎﺑﻞ ﻟﻠﻮﺻﻮﻝ ﺑﺸﻜﻞ ﻣﻨﺎﺳﺐ ﻟﺘﻘﻨﻴﺔ ﺍﻟﻮﺭﺍﺛﺔ ‪.‬‬

‫ﺭﲟﺎ ﺗﻘﻮﻝ ﺇﻥ ﺫﻟﻚ ﺧﺮﻭﺝ ﻋﻦ ﻗﺎﻋﺪﺓ ﺍﻟﺘﻐﻠﻴﻒ ﺍﻟﻜﺎﻣﻞ ﰲ ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴﺔ )ﺍﻟﱵ ﺗﻘﻮﻝ ﺑﻴﺎﻧﺎﺕ ﳏﻠﻴﺔ ﻣﻨﺎﻫﺞ ﻋﺎﻣﺔ( ‪ ،‬ﺍﳉﻮﺍﺏ‬
‫ﻧﻌﻢ ﺇﱃ ﺣﺪ ﻣﺎ ‪ ،‬ﻭﻟﺬﻟﻚ ﻋﻠﻴﻨﺎ ﺃﻥ ﻧﻜﻮﻥ ﻣﻨﺘﺒﻬﲔ ﺃﻧﻨﺎ ﻟﻦ ﳓﺼﻞ ﻋﻠﻰ ﻛﺎﻣﻞ ﻣﻴﺰﺍﺕ ﺍﻟﺘﻐﻠﻴﻒ ﻣﺎﱂ ﻧﺘﺒﻌﺔ ﺑﺸﻜﻞ ﺟﻴﺪ ‪،‬‬
‫ﻻﺣﻆ ﻣﺜﻼ ﰲ ﺣﺎﻟﺔ ﻗﻤﻨﺎ ﺑﺘﻮﺭﻳﺚ ﻋﺸﺮﺍﺕ ﺍﻷﺻﻨﺎﻑ ﻣﻦ ﺻﻨﻒ ﻣﺎ ‪ ،‬ﺇﻥ ﺗﻐﻴﲑ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﶈﻤﻴﺔ ‪ Protected‬ﰲ ﻫﺬﺍ‬
‫ﺍﻟﺼﻨﻒ ﺭﲟﺎ ﻳﻀﻄﺮﻧﺎ ﻟﺘﻐﲑ ﻣﺎﻳﻘﺎﺑﻠﻬﺎ ﰲ ﻛﻞ ﻣﻦ ﺍﻷﺻﻨﺎﻑ ﺍﳌﺸﺘﻘﺔ ‪.‬‬

‫ﺑﻜﻠﻤﺔ ﺃﺧﺮﻯ ﺍﳌﺮﻭﻧﺔ ‪ ،‬ﻗﺎﺑﻠﻴﺔ ﺍﻟﺘﻮﺳﻊ ‪ ،‬ﺍﻟﺘﻐﻠﻴﻒ ‪ ،‬ﻏﺎﻟﺒﺎ ﻣﺎ ﺗﻜﻮﻥ ﺃﻫﺪﺍﻑ ﻣﺘﻨﺎﺯﻋﺔ ‪ ،‬ﻭﻣﻦ ﺍﻟﺼﻌﺐ ﲢﻘﻴﻘﻬﺎ ﲨﻴﻌﺎ ‪،‬‬
‫ﻋﻨﺪﻣﺎ ﳛﺼﻞ ﺫﻟﻚ ﻋﻠﻴﻚ ﺃﻥ ﺗﻔﻀﻴﻞ ﺍﻟﺘﻐﻠﻴﻒ ﻣﻦ ﺑﻴﻨﻬﺎ ‪ .‬ﺇﺫﺍ ﻛﺎﻥ ﻣﻦ ﺍﳌﻤﻜﻦ ﲢﻘﻴﻖ ﺫﻟﻚ ﺑﺪﻭﻥ ﺍﻟﺘﻀﺤﻴﺔ ﺑﺎﳌﺮﻭﻧﺔ ﻓﺈﻥ‬

‫‪٣٢‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺫﻟﻚ ﺳﻴﻜﻮﻥ ﳑﺘﺎﺯﺍ ‪ .‬ﻏﺎﻟﺒﺎ ﻣﺎ ﻳﺘﻢ ﲢﻘﻴﻖ ﻫﺬﺍ ﺍﳊﻞ ﺍﻟﻮﺳﻄﻲ ﺑﺈﺳﺘﺨﺪﺍﻡ ﻣﺎﻳﻌﺮﻑ ﺑﺎﳌﻨﺎﻫﺞ ﺍﻹﻓﺘﺮﺍﺿﻴﺔ ﻭﺍﻟﱵ ﺳﻨﺄﰐ ﻋﻠﻰ‬
‫ﺫﻛﺮﻫﺎ ﻗﺮﻳﺒﺎ ﲢﺖ ﻋﻨﻮﺍﻥ ﺍﻟﺘﻐﻠﻴﻒ ﺍﳌﺘﺄﺧﺮ ﻭﺗﻌﺪﺩﻳﺔ ﺍﻷﺷﻜﺎﻝ ‪ .‬ﻭﺭﲟﺎ ﺇﺫﺍ ﱂ ﲣﺘﺮ ﺍﻟﺘﻐﻠﻴﻒ ﻣﻦ ﻫﺬﺓ ﺍﳊﻠﻮﻝ ﻣﻦ ﺃﺟﻞ‬
‫ﲢﻘﻴﻖ ﺳﺮﻋﺔ ﰲ ﻛﺘﺎﺑﺔ ﺍﻟﺸﻔﺮﺓ ﻣﺜﻼ ‪ ،‬ﻓﺈﻧﻚ ﻋﻨﺪﻫﺎ ﻟﻦ ﺗﻜﻮﻥ ﻣﺘﺒﻊ ﻟﻘﻮﺍﻋﺪ ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴﺔ ﺑﺸﻜﻞ ﺟﻴﺪ ‪.‬‬

‫ﺩﺧﻮﻝ ﺑﻴﺎﻧﺎﺕ ﳏﻤﻴﺔ ﻟﺼﻨﻒ ﺁﺧﺮ ‪: Protected Hack‬‬

‫ﳏﺪﺩﺍﺕ ﺍﻟﻮﺻﻮﻝ ‪ Private‬ﻭ ‪ Protected‬ﺗﺴﻤﺢ ﺑﺎﻟﺪﺧﻮﻝ ﺇﱃ ﺑﻴﺎﻧﺎ‪‬ﺎ ﻣﻦ ﻧﻔﺲ ﺍﻟﻮﺣﺪﺓ ﻓﻘﻂ ‪ ،‬ﺍﳉﺪﻳﺮ ﺑﺎﻟﺬﻛﺮ ﻫﻨﺎ ﺃﻧﺔ‬
‫ﻣﻦ ﺍﳌﻤﻜﻦ ﺍﻟﺪﻭﺭﺍﻥ ﻋﻠﻰ ﺍﳌﻮﺿﻮﻉ ﰲ ﺣﺎﻟﺔ ﺍﶈﺪﺩ ‪ Protected‬ﻭﺍﻟﺪﺧﻮﻝ ﺇﱃ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﶈﻤﻴﺔ ﺍﳋﺎﺻﺔ ﺑﺼﻨﻒ ﻣﺎ ‪.‬‬

‫ﺍﻟﻄﺮﻳﻘﺔ ﺗﻌﺘﻤﺪ ﻋﻠﻰ ﻣﺎﺷﺮﺣﻨﺎﺓ ﺳﺎﺑﻘﺎ ‪ ،‬ﺃﻧﻪ ﳝﻜﻦ ﺍﻟﻮﺻﻮﻝ ﺇﱃ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺍﶈﻤﻴﺔ ﻟﺼﻨﻒ ﻣﻦ ﺍﻷﺻﻨﺎﻑ ﺍﳌﺸﺘﻘﺔ ﻣﻨﻪ ‪.‬‬

‫ﻟﺬﻟﻚ ﻧﻘﻮﻡ ﺑﺈﺷﺘﻘﺎﻕ ﺻﻨﻒ ﺟﺪﻳﺪ ﻣﻦ ﺍﻟﺼﻨﻒ ﺍﻟﺬﻱ ﻧﺮﻳﺪ ﺩﺧﻮﻝ ﺑﻴﺎﻧﺎﺗﺔ ﻣﺜﻼ ﻧﺸﺘﻖ ﺍﻟﺼﻨﻒ ‪ TtestHack‬ﻣﻦ ﺍﻟﺼﻨﻒ‬
‫‪ ،Ttest‬ﻭﻋﻠﻰ ﺇﻓﺘﺮﺍﺽ ﺍﳌﺘﻐﲑ ‪ ProtectedData‬ﻣﻌﺮﻑ ﻛﻤﺘﻐﲑ ﳏﻤﻲ ﺿﻤﻦ ﺍﻟﺼﻨﻒ ‪ Ttest‬ﻛﺎﻟﺘﺎﱄ ‪:‬‬
‫‪type‬‬
‫‪Ttest = class‬‬
‫‪protected‬‬
‫;‪ProtectedData: Integer‬‬
‫;‪end‬‬

‫ﻓﺈﻧﻨﺎ ﻧﺴﺘﻄﻴﻊ ﺃﻥ ﻧﺴﺘﺨﺪﻡ ﺍﻟﻄﺮﻳﻘﺔ ﺍﻟﺘﺎﻟﻴﺔ ﻟﺪﺧﻮﻝ ﺍﳌﺘﻐﲑ ‪: ProtectedData‬‬


‫‪type‬‬
‫;)‪TtestHack = class (Ttest‬‬

‫…‬
‫‪var‬‬
‫;‪Obj: Ttest‬‬
‫‪begin‬‬
‫;‪Obj := Ttest.Create‬‬
‫;‪TtestHack (Obj).ProtectedData := 20‬‬

‫‪٣٣‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺗﻄﺒﻴﻖ ﻋﻤﻠﻲ ‪:‬‬

‫ﻛﻠﻨﺎ ﻧﺘﻌﺎﻣﻞ ﻣﻊ ﺍﻟﻌﻨﺼﺮ ﺍﳉﻤﻴﻞ ‪ ، DBNavigator‬ﻭﻟﻜﻦ ﻫﺬﺍ ﺍﻟﻌﻨﺼﺮ ﻻ ﳛﻮﻱ ﺧﺎﺻﻴﺔ ﻟﻀﺒﻂ ﺍﻟﻠﻮﻥ ‪ ،‬ﺇﺫﺍ ﻋﻠﻤﺖ ﺃﻥ‬
‫ﺍﳌﺘﺤﻮﻝ ‪ Color‬ﻣﺘﺤﻮﻝ ﳏﻤﻲ ﻟﻠﺼﻨﻒ ‪ TDBNavigator‬ﺇﻛﺘﺐ ﺷﻔﺮﺓ ﲢﻮﻳﻞ ﺍﻟﻠﻮﻥ ﺇﱃ ﺍﻷﲪﺮ ‪.‬‬

‫ﺍﳊﻞ ‪:‬‬

‫ﺃﻭﻻ ﺇﺿﺒﻂ ﺍﳋﺎﺻﻴﺔ ‪ Flat‬ﻟﻠﻨﺎﻓﻴﻐﻴﺘﻮﺭ ﺇﱃ ‪. True‬‬

‫ﺛﺎﻧﻴﺎ ﺃﺿﻒ ﺷﻔﺮﺓ ﻣﺸﺎ‪‬ﺔ ﻟﻶﺗﻴﺔ ‪:‬‬


‫; )‪type NewNav=class(TDBNavigator‬‬

‫;)‪procedure Tform1.Button1Click(Sender: Tobject‬‬

‫‪begin‬‬

‫;‪NewNav(DBNavigator1).Color:=clred‬‬

‫;‪end‬‬

‫ﻻﺑﺪ ﻣﻦ ﺍﻹﺷﺎﺭﺓ ﺃﻥ ﻫﺬﺓ ﺍﻟﻌﻤﻠﻴﺔ ﻟﻴﺴﺖ ﻗﻴﺎﺳﻴﺔ ‪ ،‬ﻣﻊ ﺃ‪‬ﺎ ﺗﺼﻠﺢ ﻭﳝﻜﻦ ﺇﺳﺘﺨﺪﺍﻣﻬﺎ ﰲ ﻛﺜﲑ ﻣﻦ ﺍﻷﺣﻴﺎﻥ ‪ ،‬ﻭﻟﻜﻦ ﳌﺎﺫﺍ‬
‫ﺟﻌﻞ ﻛﺎﺗﺐ ﺍﻟﺼﻨﻒ ﺍﻷﺳﺎﺳﻲ ﺍﻟﺒﻴﺎﻧﺎﺕ ﳏﻤﻴﺔ ﻟﻮ ﺃﻧﺔ ﻳﺮﻳﺪ ﻣﺸﺎﺭﻛﺘﻬﺎ ‪ ،‬ﻻﺣﻆ ﻣﺜﻼ ﰲ ﺍﳌﺜﺎﻝ ﺍﻟﺴﺎﺑﻖ ﺃﻧﻨﺎ ﺃﺿﻄﺮﺭﻧﺎ‬
‫ﻟﻀﺒﻂ ﺍﳋﺎﺻﻴﺔ ‪ Flat‬ﻭﻟﻦ ﺗﻈﻬﺮ ﺍﻟﺘﻐﲑﺍﺕ ﺑﻼ ﺫﻟﻚ ‪ ،‬ﺍﳋﻼﺻﺔ ﳝﻜﻨﻚ ﺇﺳﺘﺨﺪﺍﻡ ﻫﺬﺓ ﺍﻟﻄﺮﻳﻘﺔ ﻟﺘﺤﻘﻴﻖ ﻏﺎﻳﺔ ﻣﺎ‪،‬‬
‫ﻭﻟﻜﻦ ﺃﺷﺪﺩ ﻋﻠﻴﻚ ﺃﻥ ﺗﺘﺄﻛﺪ ﻣﻦ ﺃ‪‬ﺎ ﺍﻟﻄﺮﻳﻘﺔ ﺍﻷﺧﲑﺓ ﻟﺬﻟﻚ ‪.‬‬

‫ﻣﻼﺣﻈﺔ ‪ :‬ﳚﺐ ﺃﻥ ﻳﻜﻮﻥ ﺗﻌﺮﻳﻒ ﺍﻟﺼﻨﻒ ﺍﳌﺸﺘﻖ ﻭ ﺷﻔﺮﺓ ﺍﻟﺪﺧﻮﻝ ﻟﻠﺼﻨﻒ ﺍﻷﺏ ﰲ ﻧﻔﺲ ﺍﻟﻮﺣﺪﺓ ‪ .‬ﺃﻱ ﺍﻟﺴﻄﺮ‬
‫;‪NewNav(DBNavigator1).Color:=clred‬‬

‫ﻭﺍﻟﺘﻌﺮﻳﻒ ; )‪type NewNav=class(TDBNavigator‬‬

‫ﳚﺐ ﺃﻥ ﻳﻜﻮﻧﺎ ﺑﻨﻔﺲ ﺍﻟﻮﺣﺪﺓ ‪ ،‬ﻭﻋﻨﺪ ﻓﺼﻠﻬﻤﺎ ﰲ ﻭﺣﺪﺍﺕ ﳐﺘﻠﻔﺔ ﻓﺈﻥ ﺍﻟﺸﻔﺮﺓ ﺍﻟﺴﺎﺑﻘﺔ ﻟﻦ ﺗﺘﺮﺟﻢ ‪.‬‬

‫‪٣٤‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﻟﻮﺭﺍﺛﺔ ﻭﺍﻟﺘﻮﺍﻓﻖ ﺑﲔ ﺍﻷﳕﺎﻁ ‪:‬‬

‫ﺍﻟﺒﺎﺳﻜﺎﻝ ﻟﻐﺔ ﳕﻮﺫﺟﻴﺔ ﻭﻣﺜﺎﻟﻴﺔ ﺑﺸﻜﻞ ﺻﺎﺭﻡ ‪ ،‬ﻭﻫﺬﺍ ﻳﻌﲏ ﺃﻧﻚ ﻟﻦ ﺗﺴﺘﻄﻴﻊ ﻣﺜﻼ ﺃﻥ ﺗﻨﺴﺐ ﻗﻴﻤﺔ ﺭﻗﻤﻴﺔ ﺇﱃ ﻗﻴﻤﺔ ﻧﺼﻴﺔ ﺃﻭ‬
‫ﺍﻟﻌﻜﺲ ﺑﺪﻭﻥ ﺇﺟﺮﺍﺀ ﲢﻮﻳﻞ ﺑﺪﻭﺍﻝ ﺍﻟﺘﺤﻮﻳﻞ ﺍﳌﻨﺎﺳﺒﺔ ﺍﻟﱵ ﺗﺰﻭﺩﻙ ﺩﻟﻔﻲ ‪‬ﺎ ‪،‬‬

‫ﻭﻟﻠﺘﺒﺴﻴﻂ ﻓﺈﻥ ﺩﻟﻔﻲ ﺗﺴﻤﺢ ﻟﻚ ﰲ ﺑﻌﺾ ﺍﻷﺣﻴﺎﻥ ﻧﺴﺐ ﳕﻄﲔ ﳐﺘﻠﻔﲔ ‪ ،‬ﰲ ﺣﺎﻝ ﻛﺎﻥ ﺃﺣﺪﳘﺎ ﻳﺴﺘﻮﻋﺐ ﺍﻵﺧﺮ ‪ ،‬ﻣﺜﻼ‬
‫ﻻﺣﻆ ﺃﻧﻨﺎ ﻧﺴﺘﻄﻴﻊ ﻧﺴﺐ ﻣﺘﺤﻮﻝ ‪ Integer‬ﺇﱃ ﻣﺘﺤﻮﻝ ‪ Real‬ﺑﺪﻭﻥ ﺃﺧﻄﺎﺀ ‪ ،،‬ﻭﺑﺎﻟﻄﺒﻊ ﺍﳊﺎﻟﺔ ﺍﳌﻌﺎﻛﺴﺔ ﻏﲑ ﺻﺤﻴﺤﺔ ‪.‬‬
‫;‪var i:integer‬‬

‫;‪r:real‬‬

‫‪begin‬‬

‫;‪r:=i‬‬ ‫‪// ok‬‬

‫;‪i:=r‬‬ ‫!!!‪//error‬‬

‫;‪End‬‬

‫ﻭﻫﺬﺍ ﺍﻹﺳﺘﺜﻨﺎﺀ ﻣﻬﻢ ﰲ ﺣﺎﻟﺔ ﺃﳕﺎﻁ ﺍﻷﺻﻨﺎﻑ ‪ ،‬ﻓﺈﺫﺍ ﻗﻤﺖ ﻣﺜﻼ ﺑﺘﻌﺮﻳﻒ ﺻﻨﻒ ﺟﺪﻳﺪ ﻣﺜﻞ ‪ Tanimal‬ﻭﺃﺷﺘﻘﻴﺖ ﻣﻨﻪ‬
‫ﺻﻨﻒ ﻭﻟﻨﻘﻞ ﻣﺜﻼ ‪ ، Tdog‬ﺗﺴﺘﻄﻴﻊ ﻋﻨﺪﻫﺎ ﺃﻥ ﺗﻨﺴﺐ ﻏﺮﺽ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ Tdog‬ﺇﱃ ﻣﺘﺤﻮﻝ ﻣﻦ ﺍﻟﺼﻨﻒ ‪، Tanimal‬‬
‫ﻹﻥ ﺍﻟﻜﻠﺐ ﺣﻴﻮﺍﻥ ‪ ،‬ﻭﻟﻜﻦ ﻟﻴﺲ ﺑﺎﻟﻀﺮﻭﺭﺓ ﺃﻥ ﻳﻜﻮﻥ ﻛﻞ ﺣﻴﻮﺍﻥ ﻛﻠﺐ ‪ ،‬ﻭﺑﻨﺎﺀ ﻋﻠﻰ ﺫﻟﻚ ﺍﻟﻌﻜﺲ ﻏﲑ ﳑﻜﻦ ‪:‬‬
‫‪var‬‬
‫;‪MyAnimal: Tanimal‬‬
‫;‪MyDog: Tdog‬‬
‫‪begin‬‬
‫;‪MyAnimal := MyDog‬‬ ‫‪// OK‬‬
‫;‪MyDog := MyAnimal‬‬ ‫!!!‪// error‬‬

‫‪٣٥‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﻟﺘﺤﺪﻳﺪ ﺍﳌﺘﺄﺧﺮ ﻭﺗﻌﺪﺩﻳﺔ ﺍﻷﺷﻜﺎﻝ ‪:‬‬

‫ﺗﻌﺘﻤﺪ ﺗﻮﺍﺑﻊ ﺍﻟﺒﺎﺳﻜﺎﻝ ﻭﺇﺟﺮﺍﺀﺍ‪‬ﺎ ﻋﺎﺩﺓ ﻋﻠﻰ ﺍﻟﺘﺤﺪﻳﺪ ﺍﻟﺴﺎﻛﻦ ﺃﻭ ﺍﳌﺒﻜﺮ )‪ ، (static or early binding‬ﻭﻫﺬﺍ ﻳﻌﲏ ﺃﻥ‬
‫ﺍﳌﺘﺮﺟﻢ ﺳﻴﻘﻮﻡ ﺑﺘﺤﻠﻴﻞ ﺍﻹﺳﺘﺪﻋﺎﺀ ﻭﺇﺳﺘﺒﺪﺍﻝ ﺍﻟﻄﻠﺐ ﺑﺈﺳﺘﺪﻋﺎﺀ ﳌﻮﻗﻊ ﺍﻟﺬﺍﻛﺮﺓ ﺍﳊﺎﻭﻱ ﻋﻠﻰ ﺍﻟﺘﺎﺑﻊ ﺃﻭ ﺍﻹﺟﺮﺍﺀ )ﻋﻨﻮﺍﻥ ﺍﻟﺮﻭﺗﲔ(‬
‫‪ ،‬ﻭﻫﺬﺍ ﻳﻌﲏ ﺍﻟﺘﺤﺪﻳﺪ ﺍﳌﺴﺒﻖ ﻟﻠﺘﺎﺑﻊ ﺃﻭ ﺍﻹﺟﺮﺍﺀ ﺍﻟﺬﻱ ﺳﻮﻑ ﻳﺘﻢ ﺇﺳﺘﺪﻋﺎﺀﺓ ‪ ،‬ﻭﻳﻘﻮﻡ ﺍﳌﺘﺮﺟﻢ ‪‬ﺬﺍ ﺍﻟﺘﺤﺪﻳﺪ ﳊﻈﺔ ﺗﺮﲨﺔ‬
‫ﺍﳌﺸﺮﻭﻉ ﻭﺑﺎﻟﺘﺎﱄ ﺍﻟﺘﺼﺮﻑ ﰲ ﻭﻗﺖ ﺍﻟﺘﻨﻔﻴﺬ ﻣﻌﺮﻭﻑ ﻭﳏﺪﺩ ﻣﻨﺬ ﺗﺮﲨﺔ ﺍﳌﺸﺮﻭﻉ ‪.‬‬

‫ﺍﳌﺘﺄﺧﺮ) ‪dynamic or‬‬ ‫ﻟﻐﺎﺕ ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ )‪ (OOP‬ﺗﺴﻤﺢ ﺑﻨﻮﻉ ﺁﺧﺮ ﻣﻦ ﺍﻟﺘﺤﺪﻳﺪ ﻳﺴﻤﻰ ﺍﻟﺘﺤﺪﻳﺪ ﺍﻟﺪﻳﻨﺎﻣﻴﻜﻲ ﺃﻭ‬
‫‪ ، (late binding‬ﻭﰲ ﻫﺬﺍ ﺍﳊﺎﻟﺔ ﻓﺈﻥ ﺍﻟﻌﻨﻮﺍﻥ ﺍﻟﻔﻌﻠﻲ ﺍﻟﺬﻱ ﺳﻮﻑ ﻳﺴﺘﺪﻋﻰ ﻟﻦ ﻳﺘﻢ ﲢﺪﻳﺪﺓ ﺣﱴ ﻭﻗﺖ ﺍﻟﺘﺸﻐﻴﻞ ‪ ،‬ﻭﻳﻌﺘﻤﺪ‬
‫ﺍﻟﺘﺤﺪﻳﺪ ﻋﻠﻰ ﳕﻂ ﺍﳌﻨﺘﺴﺦ ﺍﻟﺬﻱ ﻗﺎﻡ ﺑﺎﻟﻄﻠﺐ ‪.‬‬

‫ﺗﺴﻤﻰ ﻫﺬﺓ ﺍﻟﺘﻘﻨﻴﺔ ﺗﻌﺪﺩﻳﺔ ﺍﻷﺷﻜﺎﻝ ‪( polymorphism)،‬ﺑﺎﻟﻴﻮﻧﺎﻧﻴﺔ ﺗﻌﲏ)‪(many forms‬ﺑﺎﻹﻧﻜﻠﻴﺰﻳﺔ ‪ ،‬ﺗﻌﺪﺩﻳﺔ ﺍﻷﺷﻜﺎﻝ ﺗﻌﲏ‬
‫ﺃﻧﻚ ﺗﻘﻮﻡ ﺑﺈﺳﺘﺪﻋﺎﺀ ﻣﻨﻬﺞ ‪ ،‬ﺗﻨﺴﺒﺔ ﳌﺘﺤﻮﻝ ‪ ،‬ﻭﻟﻜﻦ ﻣﺎﻫﻮ ﺍﳌﻨﻬﺞ ﺍﻟﺬﻱ ﻗﺎﻣﺖ ﺩﻟﻔﻲ ﻓﻌﻠﻴﺎ ﺑﺈﺳﺘﺪﻋﺎﺀﺓ ﻓﺈﻥ ﺫﻟﻚ ﻳﻌﺘﻤﺪ ﻋﻠﻰ‬
‫ﳕﻂ ﺍﻟﻐﺮﺽ ﺍﻟﺬﻱ ﻧﺴﺐ ﺇﻟﻴﺔ ﺍﳌﺘﻐﻴﲑ ‪ ،‬ﻭﺩﻟﻔﻲ ﻟﻦ ﺗﺴﺘﻄﻴﻊ ﲢﺪﻳﺪ ﺻﻨﻒ ﻏﺮﺽ ﻫﺬﺍ ﺍﳌﺘﻐﲑ ﺣﱴ ﻭﻗﺖ ﺍﻟﺘﺸﻐﻴﻞ ‪.‬‬

‫ﻣﻴﺰﺓ ﺗﻌﺪﺩﻳﺔ ﺍﻷﺷﻜﺎﻝ ﺃ‪‬ﺎ ﺗﺴﻤﺢ ﺑﻜﺘﺎﺑﺔ ﺃﻛﻮﺍﺩ ﺃﺑﺴﻂ ‪ ،‬ﻭﺍﻟﺘﻌﺎﻣﻞ ﻣﻊ ﺃﻏﺮﺍﺽ ﻣﺘﺒﺎﻳﻨﺔ ﺍﻟﻨﻤﻂ ﻛﻤﺎ ﻟﻮﺃ‪‬ﺎ ﻣﺘﺸﺎ‪‬ﻪ ﲝﻴﺚ ﻳﺘﻢ‬
‫ﺍﳊﺼﻮﻝ ﻋﻠﻰ ﺍﻟﺘﺼﺮﻑ ﺍﳌﻨﺎﺳﺐ ﰲ ﺯﻣﻦ ﺍﻟﺘﺸﻐﻴﻞ ‪.‬‬

‫ﻟﺘﻮﺿﻴﺢ ﺫﻟﻚ ﺩﻋﻨﺎ ﻋﻠﻰ ﺳﺒﻴﻞ ﺍﳌﺜﺎﻝ ﻧﻔﺘﺮﺽ ﺃﻥ ﺻﻨﻒ ﻣﺎ ﻭﺻﻨﻒ ﻣﺸﺘﻖ ﻣﻨﻪ ﻳﻌﺮﻓﺎﻥ ﻧﻔﺲ ﺍﳌﻨﻬﺞ ‪ ،‬ﻭﳍﺬﺍ ﺍﳌﻨﻬﺞ ﲢﺪﻳﺪ‬
‫ﻣﺘﺄﺧﺮ ‪ ،‬ﻣﺜﻼ ﺍﻟﺼﻨﻔﺎﻥ ‪ Tanimal‬ﻭ ‪ Tdog‬ﻳﻌﺮﻑ ﻛﻞ ﻣﻨﻬﻤﺎ ﺍﳌﻨﻬﺞ ‪ Voice‬ﻭﺍﻟﺬﻱ ﳜﺮﺝ ﺻﻮﺕ ﺍﳊﻴﻮﺍﻥ ﺍﳌﺨﺘﺎﺭ ‪،‬‬
‫ﻓﺈﺫﺍ ﻋﺮﻓﻨﺎ ﺍﳌﺘﻐﲑ ‪ MyAnimal‬ﻭﺍﻟﺬﻱ ﺳﻴﺸﲑ ﰲ ﺯﻣﻦ ﺍﻟﺘﺸﻐﻴﻞ ﺇﻣﺎ ﻟﻐﺮﺽ ﻣﻦ ﺍﻟﻨﻮﻉ ‪ Tanimal‬ﺃﻭ ﻟﻐﺮﺽ ﻣﻦ ﺍﻟﻨﻮﻉ ‪Tdog‬‬

‫‪ ،‬ﺑﺎﻟﺘﺎﱄ ﻓﺈﻥ ﺍﳌﻨﻬﺞ ﺍﻟﺬﻱ ﺳﻴﺘﻢ ﺇﺳﺘﺪﻋﺎﺀﺓ ﻓﻌﻠﻴﺎ ﻳﺘﻢ ﲢﺪﻳﺪﺓ ﻭﻗﺖ ﺍﻟﺘﺸﻐﻴﻞ ﺇﺫﺍ ﻛﺎﻥ ﻣﻨﻬﺞ ‪ Voice‬ﺍﳋﺎﺹ ﺏ ‪ Tanimal‬ﺃﻭ‬
‫‪ Voice‬ﺍﳋﺎﺹ ﺏ‪ ، Tdog‬ﺣﺴﺐ ﺍﻟﻨﻤﻂ ﺍﻟﺬﻱ ﻳﺸﲑ ﺇﻟﻴﺔ ‪. MyAnimal‬‬

‫‪OverRide‬‬ ‫ﻟﺘﺤﻘﻴﻖ ﺫﻟﻚ ﻧﻌﺮﻑ ﺍﳌﻨﻬﺞ ‪ Voice‬ﻋﻠﻰ ﺷﻜﻞ ‪) Virtual‬ﺇﻓﺘﺮﺍﺿﻲ( ﰲ ﺍﻟﺼﻨﻒ ﺍﻷﺳﺎﺳﻲ ‪ ،‬ﻭﻋﻠﻰ ﺷﻜﻞ‬
‫)ﻣﻬﻴﻤﻦ( ﰲ ﺍﻟﺼﻨﻒ ﺍﳌﺸﺘﻖ ‪ ،‬ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﻟﻜﻠﻤﺘﺎﻥ ﺍﳌﻔﺘﺎﺣﻴﺘﺎﻥ ‪ virtual‬ﻭ ‪. override‬‬
‫‪Type‬‬
‫‪Tanimal = class‬‬
‫‪public‬‬
‫;‪function Voice: string; virtual‬‬

‫)‪Tdog = class (Tanimal‬‬


‫‪public‬‬
‫;‪function Voice: string; override‬‬

‫‪٣٦‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻓﺈﺫﺍ ﻋﺮﻓﻨﺎ ﺍﳌﺘﻐﲑ ‪ MyAnimal‬ﻣﻦ ﺍﻟﺼﻨﻒ ‪ Tanimal‬ﻓﺈﻥ ﻧﺴﺘﻄﻴﻊ ﺑﻨﺎﺀﺓ ﻛﻐﺮﺽ ﻣﻦ ‪ Tanimal‬ﺃﻭ ‪ ، Tdog‬ﺣﺴﺐ‬
‫ﻗﻮﺍﻋﺪ ﺍﻟﺘﻮﺍﻓﻖ ﺑﲔ ﺍﻷﳕﺎﻁ ﺍﻟﱵ ﺭﺃﻳﻨﺎﻫﺎ ﰲ ﺍﻟﻔﻘﺮﺓ ﺍﻟﺴﺎﺑﻘﺔ ﻭﺑﺎﻟﺘﺎﱄ ﻧﺴﺘﻄﻴﻊ ﺇﺳﺘﺪﻋﺎﺀ ﻛﻼ ﻣﻦ ‪:‬‬
‫;‪MyAnimal := Tdog.Create‬‬

‫;‪MyAnimal := Tanimal.Create‬‬

‫ﻭﺑﺎﻟﺘﺎﱄ ﻓﺈﻧﻨﺎ ﻧﺴﺘﻄﻴﻊ ﰲ ﺯﻣﻦ ﺍﻟﺘﺸﻐﻴﻞ ﺃﻥ ﻧﺸﲑ ﺇﱃ ﻏﺮﺽ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ Tdog‬ﺃﻭ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ Tanimal‬ﻭﻛﻞ ﻣﻨﻬﻤﺎ ﻟﻪ‬
‫ﺍﳌﻨﻬﺞ ‪ ، Voice‬ﻭﻋﻨﺪﻣﺎ ﳓﺎﻭﻝ ﺇﺳﺘﺪﻋﺎﺀ ﻫﺬﺍ ﺍﳌﻨﻬﺞ ﻣﻦ ﺍﻟﻐﺮﺽ ‪ MyAnimal‬ﺍﻟﺬﻱ ﻗﺪ ﻳﺸﲑ ﺇﱃ ﺃﻱ ﻣﻨﻬﻤﺎ ‪ ،‬ﻓﺈﻥ ﺗﺼﺮﻑ‬
‫ﻣﺘﺮﺟﻢ ﺍﻟﻠﻐﺔ ‪ Compiler‬ﻳﻜﻮﻥ ﳐﺘﻠﻔﺎ ﻋﻦ ﺍﳊﺎﻟﺔ ﺍﻟﺴﺎﻛﻨﺔ ﻟﻺﺳﺘﺪﻋﺎﺀ ﺍﻟﱵ ﻳﺘﻢ ﲢﺪﻳﺪ ﻓﻴﻬﺎ ﻋﻨﻮﺍﻥ ﺍﻹﺳﺘﺪﻋﺎﺀ ﺳﻠﻔﺎ ‪ ،‬ﻭﺳﻴﻌﺘﻤﺪ‬
‫ﻋﻠﻰ ﻧﻮﻉ ﺍﻟﻐﺮﺽ ﺍﳊﺎﱄ ﻟﺘﺤﺪﻳﺪ ﺃﻱ ﻣﻨﻬﺞ ﳚﺐ ﺃﻥ ﻳﺴﺘﺪﻋﻲ ‪:‬‬
‫;‪MyAnimal := Tdog.Create‬‬

‫‪MyAnimal.Voice‬‬ ‫‪//‬‬ ‫‪Tdog.Voice‬‬

‫‪// OR ..‬‬

‫;‪MyAnimal := Tanimal.Create‬‬

‫‪MyAnimal.Voice‬‬ ‫‪//‬‬ ‫‪Tanimal.Voice‬‬

‫ﺇﻥ ﺫﻟﻚ ﳛﺪﺙ ﻓﻘﻂ ﻹﻥ ﺍﳌﻨﻬﺞ ﺇﻓﺘﺮﺍﺿﻲ ‪ Virtual‬ﻛﻤﺎ ﻋﺮﻓﻨﺎﺓ ‪ ،‬ﻭﺑﻜﻠﻤﺔ ﺃﺧﺮﻯ ﻓﺈﻥ ﻫﺬﺍ ﺍﻹﺳﺘﺪﻋﺎﺀ ﻟـ‬
‫‪ MyAnimal.Voice‬ﻣﺘﻮﺍﻓﻖ ﻣﻊ ﻛﻞ ﺍﻷﺻﻨﺎﻑ ﺍﳌﺴﺘﻘﺒﻠﻴﺔ ﺍﳌﺸﺘﻘﻪ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ ، Tanimal‬ﺣﱴ ﺍﻟﱵ ﱂ ﺗﺘﻢ ﻛﺘﺎﺑﺘﻬﺎ ﺑﻌﺪ ‪.‬‬

‫ﻣﻼﺣﻈﺔ ‪:‬‬

‫ﻫﺬﺍ ﻫﻮ ﺍﻟﺴﺒﺐ ﺍﻟﺘﻘﲏ ﻟﻜﻮﻥ ﺍﻟﱪﳎﺔ ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ ﺗﻔﻀﻞ ﺍﻟﻘﺪﺭﺓ ﻋﻠﻰ ﺍﻟﺘﻮﺳﻊ ﻭ ﺇﻋﺎﺩﺓ ﺍﻹﺳﺘﻌﻤﺎﻝ )‪ ، (reusability‬ﺣﻴﺚ‬
‫ﺃﻧﻚ ﺗﺴﺘﻄﻴﻊ ﻛﺘﺎﺑﺔ ﺷﻔﺮﺍﺕ ﺗﺴﺘﺨﺪﻡ ﺃﺻﻨﺎﻑ ﻣﻦ ﺑﻨﻴﺔ ﻭﺭﺍﺛﻴﺔ ﻣﻌﻘﺪﺓ ﺩﻭﻥ ﺃﻱ ﻣﻌﺮﻓﺔ ﺑﺎﻷﺻﻨﺎﻑ ﺍﶈﺪﺩﺓ ﺍﻟﱵ ﺗﺸﻜﻞ ﺟﺰﺀ ﻣﻦ‬
‫ﻫﺬﺓ ﺍﻟﺒﻨﻴﺔ ‪ ،‬ﻭﺑﻜﻠﻤﺔ ﺃﺧﺮﻯ ﺗﺒﻘﻰ ﻫﺬﺓ ﺍﻟﺒﻨﻴﺔ ﺍﻟﻮﺭﺍﺛﻴﺔ ﻭﺑﺮﺍﳎﻚ ﺍﻟﱵ ﺗﺴﺘﺨﺪﻡ ﻫﺬﺓ ﺍﻟﺒﻨﻴﺔ ﻗﺎﺑﻠﺔ ﻟﻠﺘﻮﺳﻊ ﻭﺍﻟﺘﻐﻴﲑ ‪ ،‬ﺣﱴ ﺑﻮﺟﻮﺩ‬
‫ﺁﺍﻻﻑ ﺍﻟﺴﻄﻮﺭ ﻣﻦ ﺍﻟﺸﻔﺮﺓ ﺍﻟﱵ ﺗﺴﺘﺨﺪﻣﻬﺎ ‪ .‬ﻭﻟﻜﻦ ﺑﺸﺮﻁ ﻭﺍﺣﺪ ﺃﺳﺎﺳﻲ ‪ :‬ﺃﻥ ﻳﻜﻮﻥ ﺍﻟﺼﻨﻒ ﺍﻟﺴﻠﻒ ﳍﺬﺓ ﺍﻟﺸﺠﺮﺓ‬
‫ﺍﻟﻮﺭﺍﺛﻴﺔ ﻣﺼﻤﻢ ﺑﻌﻨﺎﻳﺔ ﻓﺎﺋﻘﺔ ‪.‬‬

‫‪٣٧‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺇﻋﺎﺩﺓ ﺗﻌﺮﻳﻒ ﺍﳌﻨﺎﻫﺞ ﻭﺍﳌﻨﺎﻫﺞ ﺍﳌﻬﻴﻤﻨﺔ‪:‬‬

‫ﻛﻤﺎ ﺭﺃﻳﻨﺎ ‪ ،‬ﳉﻌﻞ ﻣﻨﻬﺞ ﻣﺘﺄﺧﺮ ﺍﻟﺘﺤﺪﻳﺪ ﻣﻬﻴﻤﻨﺎ ﰲ ﺻﻨﻒ ﻣﺸﺘﻖ ﻧﻘﻮﻡ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﻟﻜﻠﻤﺔ ﺍﳌﻔﺘﺎﺣﻴﺔ ‪ ، override‬ﺗﺬﻛﺮ ﺃﻧﻚ‬
‫ﺫﻟﻚ ﳝﻜﻦ ﺃﻥ ﳛﺪﺙ ﻓﻘﻂ ﺇﺫﺍ ﻛﺎﻥ ﺍﳌﻨﻬﺞ ﻣﻌﺮﻓﺎ ﻛﻤﻨﻬﺞ ﺇﻓﺘﺮﺍﺿﻲ )‪ (virtual‬ﰲ ﺍﻟﺼﻨﻒ ﺍﻟﺴﻠﻒ ‪،‬ﺃﻱ ﺩﻳﻨﺎﻣﻴﻜﻲ‬
‫)‪ (Dynamic‬ﺃﻣﺎ ﺇﺫﺍ ﻛﺎﻥ ﻣﻌﺮﻓﺎ ﻛﻤﻨﻬﺞ ﺳﺎﻛﻦ )‪ (static‬ﻓﻼ ﺗﻮﺟﺪ ﻃﺮﻳﻘﺔ ﻋﻨﺪﻫﺎ ﻟﺘﻔﻌﻴﻞ ﺍﻟﺘﺤﺪﻳﺪ ﺍﳌﺘﺄﺧﺮ )‪(late binding‬‬
‫ﺇﻻ ﺑﺘﻐﻴﲑ ﺷﻔﺮﺓ ﺍﻟﺼﻨﻒ ﺍﻟﺴﻠﻒ ﻧﻔﺴﻬﺎ ‪.‬‬

‫ﻗﻮﺍﻋﺪ ﻫﺬﺓ ﺍﻟﻌﻤﻠﻴﺔ ﻟﻴﺴﺖ ﺻﻌﺒﺔ ‪ :‬ﺍﳌﻨﻬﺞ ﺍﳌﻌﺮﻑ ﻛﻤﻨﻬﺞ ﺳﺎﻛﻦ )‪ (Static‬ﺳﻴﺒﻘﻰ ﺳﺎﻛﻨﺎ ﰲ ﻛﻞ ﺍﻷﺻﻨﺎﻑ ﺍﳌﻮﺭﺛﺔ ‪ ،‬ﺣﱴ‬
‫ﺗﻘﻮﻡ ﺑﺈﺧﻔﺎﺋﺔ ﲟﻨﻬﺞ ﺇﻓﺘﺮﺍﺿﻲ ﺟﺪﻳﺪ ﳛﻤﻞ ﻧﻔﺲ ﺍﻹﺳﻢ ‪ .‬ﺍﳌﻨﻬﺞ ﺍﳌﻌﺮﻑ ﻛﻤﻨﻬﺞ ﺇﻓﺘﺮﺍﺿﻲ )‪ (Vertioal‬ﻳﺒﻘﻰ ﻣﺘﺄﺧﺮ ﺍﻟﺘﺤﺪﻳﺪ‬
‫ﰲ ﻛﻞ ﺍﻷﺻﻨﺎﻑ ﺍﳌﻮﺭﺛﺔ )ﺇﻻ ﺇﺫﺍ ﻗﻤﺖ ﺑﺈﺧﻔﺎﺋﺔ ﲟﻨﻬﺞ ﺳﺎﻛﻦ ‪،‬ﻭﺫﻟﻚ ﻳﻌﺘﱪ ﻋﻤﻼ ﻏﺒﻴﺎ ﺟﺪﺍ ( ‪ .‬ﻻﺗﻮﺟﺪ ﻃﺮﻳﻘﺔ ﻟﺘﻐﻴﲑ ﻫﺬﺍ‬
‫ﺍﻟﺘﺼﺮﻑ ‪ ،‬ﻹﻥ ﺍﳌﺘﺮﺟﻢ ﺳﻴﻮﻟﺪ ﺷﻔﺮﺓ ﳐﺘﻠﻔﺔ ﻣﻦ ﺃﺟﻞ ﻣﻨﺎﻫﺞ ﺍﻟﺘﺤﺪﻳﺪ ﺍﳌﺘﺄﺧﺮ ‪.‬‬

‫ﻹﻋﺎﺩﺓ ﺗﻌﺮﻳﻒ ﻣﻨﻬﺞ ﺳﺎﻛﻦ ‪ ،‬ﺃﺿﻒ ﺗﻌﺮﻳﻒ ﺍﳌﻨﻬﺞ ﰲ ﺍﻟﺼﻨﻒ ﺍﳌﺸﺘﻖ ﺑﺪﻭﻥ ﺃﻱ ﺇﺿﺎﻓﺎﺕ ‪ ،‬ﻭﺑﺈﻣﻜﺎﻧﺔ ﺃﻥ ﳝﻠﻚ ﺑﺎﺭﻣﺘﺮﺍﺕ‬
‫ﳐﺘﻠﻔﺔ ﻋﻦ ﺍﳌﻨﻬﺞ ﺍﻷﺻﻞ ﰲ ﻫﺬﺓ ﺍﳊﺎﻟﺔ ‪ .‬ﳉﻌﻞ ﻣﻨﻬﺞ ﺇﻓﺘﺮﺍﺿﻲ ﻣﺎ ﻣﻨﻬﺠﺎ ﻣﻬﻴﻤﻨﺎ ‪ ،‬ﳚﺐ ﺃﻥ ﺗﺴﺘﺨﺪﻡ ﺍﻟﻜﻠﻤﺔ ﺍﳌﻔﺘﺎﺣﻴﺔ‬
‫‪ ، override‬ﻭﰲ ﻫﺬﺓ ﺍﳊﺎﻟﺔ ﳚﺐ ﺃﻥ ﳝﻠﻚ ﺍﳌﻨﻬﺞ ﻧﻔﺲ ﺑﺎﺭﻣﺘﺮﺍﺕ ﺍﳌﻨﻬﺞ ﺍﻷﺻﻞ ‪.‬‬
‫‪type‬‬
‫‪TmyClass = class‬‬
‫;‪procedure One; virtual‬‬
‫}‪procedure Two; {static method‬‬
‫;‪end‬‬

‫)‪TmyDerivedClass = class (MyClass‬‬


‫;‪procedure One; override‬‬
‫;‪procedure Two‬‬
‫;‪end‬‬

‫ﺗﺴﺘﻄﻴﻊ ﺟﻌﻞ ﻣﻨﻬﺞ ﻣﺎ ﻣﻬﻴﻤﻨﺎ ﺑﻄﺮﻳﻘﺘﲔ ‪ :‬ﺍﻷﻭﱃ ﻫﻲ ﺇﺳﺘﺒﺪﺍﻝ ﻣﻨﻬﺞ ﺍﻟﺼﻨﻒ ﺍﻷﺻﻞ ﺑﻮﺍﺣﺪ ﺟﺪﻳﺪ ‪.‬‬

‫ﺍﻟﺜﺎﻧﻴﺔ ﻫﻲ ﺇﺿﺎﻓﺔ ﺷﻔﺮﺍﺕ ﺇﺿﺎﻓﻴﺔ ﺇﱃ ﺍﳌﻨﻬﺞ ﺍﳌﻮﺟﻮﺩ ‪ ،‬ﻭﻟﺘﺤﻘﻴﻖ ﺫﻟﻚ ﻧﺴﺘﺨﺪﻡ ﺍﻟﻜﻠﻤﺔ ﺍﳌﻔﺘﺎﺣﻴﺔ ‪ inherited‬ﻹﺳﺘﺪﻋﺎﺀ‬
‫ﺍﳌﻨﻬﺞ ﺍﳋﺎﺹ ﺑﺎﻟﺼﻨﻒ ﺍﻷﺻﻞ ﺿﻤﻦ ﺷﻔﺮﺓ ﻣﻨﻬﺞ ﺍﻟﺼﻨﻒ ﺍﳌﺸﺘﻖ ‪.‬‬
‫;‪procedure TmyDerivedClass.One‬‬
‫‪begin‬‬
‫‪// new code‬‬
‫…‬
‫;‪inherited One‬‬ ‫‪// call inherited procedure MyClass.One‬‬

‫;‪end‬‬

‫‪٣٨‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﳌﻨﺎﻫﺞ ﺍﻹﻓﺘﺮﺍﺿﻴﺔ ﻣﻘﺎﺑﻞ ﺍﻟﺪﻳﻨﺎﻣﻴﻜﻴﺔ ‪: Virtual versus Dynamic Methods‬‬

‫ﻧﺴﺘﻄﻴﻊ ﰲ ﺩﻟﻔﻲ ﺗﻔﻌﻴﻞ ﺍﻟﺘﺤﺪﻳﺪ ﺍﳌﺘﺄﺧﺮ ﺑﻄﺮﻳﻘﺘﲔ ‪ .‬ﺇﻣﺎ ﺗﻌﺮﻳﻒ ﺍﳌﻨﻬﺞ ﻛﻤﻨﻬﺞ ﺇﻓﺘﺮﺍﺿﻲ ﻛﻤﺎ ﺭﺃﻳﻨﺎ ﺳﺎﺑﻘﺎ ‪ ،‬ﺃﻭ ﺗﻌﺮﻳﻔﺔ‬
‫ﻛﻤﻨﻬﺞ ﺩﻳﻨﺎﻣﻴﻜﻲ ‪ .‬ﺍﻟﻌﺒﺎﺭﺓ ﺍﻟﻨﺤﻮﻳﺔ ﻟﻠﻜﻠﻤﺘﺎﻥ ﺍﳌﻔﺘﺎﺣﻴﺘﺎﻥ ) ‪ (virtual‬ﻭ )‪ (dynamic‬ﻫﻲ ﻧﻔﺴﻬﺎ ﲤﺎﻣﺎ ‪ ،‬ﻭﻧﺘﻴﺠﺔ‬
‫ﺇﺳﺘﺨﺪﺍﻣﻬﻤﺎ ﻫﻲ ﻧﻔﺴﻬﺎ ﺃﻳﻀﺎ ‪ ،‬ﻭﺍﻹﺧﺘﻼﻑ ﺑﻴﻨﻬﻤﺎ ﻓﻘﻂ ﻫﻮ ﺍﻵﻟﻴﺔ ﺍﻟﺪﺍﺧﻠﻴﺔ ﺍﻟﱵ ﻳﺘﺒﻌﻬﺎ ﺍﳌﺘﺮﺟﻢ ﻟﺘﻨﻔﻴﺬ ﺍﻟﺘﺤﺪﻳﺪ ﺍﳌﺘﺄﺧﺮ ‪.‬‬

‫ﺍﳌﻨﺎﻫﺞ ﺍﻹﻓﺘﺮﺍﺿﻴﺔ ﺗﻌﺘﻤﺪ ﻋﻠﻰ ﺟﺪﻭﻝ ﺍﳌﻨﺎﻫﺞ ﺍﻹﻓﺘﺮﺍﺿﻴﺔ ‪ VMT‬ﺃﻭ)‪ ، (virtual method table‬ﻭﺍﻟﺬﻱ ﳜﺰﻥ ﺿﻤﻨﺔ ﻋﻨﺎﻭﻳﻦ‬
‫ﺍﳌﻨﺎﻫﺞ ﰲ ﺍﻟﺬﺍﻛﺮﺓ ‪ ،‬ﻭﻳﺴﻤﻰ ﺃﺣﻴﺎﻧﺎ ‪ ، Vtable‬ﺣﻴﺚ ﺳﻴﻘﻮﻡ ﺍﳌﺘﺮﺟﻢ ﺑﺘﻮﻟﻴﺪ ﺷﻔﺮﺓ ﺍﻟﻘﻔﺰ ﺇﱃ ﻋﻨﻮﺍﻥ ﺍﻟﺬﺍﻛﺮﺓ ﺍﳌﺨﺰﻥ ﰲ‬
‫ﺍﻟﺴﺠﻞ ‪ n‬ﳉﺪﻭﻝ ﺍﳌﻨﺎﻫﺞ ﺍﻹﻓﺘﺮﺍﺿﻴﺔ ‪ ،‬ﺗﺴﻤﺢ ﺟﺪﺍﻭﻝ ﺍﳌﻨﺎﻫﺞ ﺍﻹﻓﺘﺮﺍﺿﻴﺔ ﺑﺘﻨﻔﻴﺬ ﺳﺮﻳﻊ ﻟﻺﺳﺘﺪﻋﺎﺀ ‪ ،‬ﻭﻟﻜﻨﻬﺎ ﺗﺘﻄﻠﺐ ﻣﺪﺧﻼ‬
‫ﺧﺎﺻﺎ ﻣﻦ ﺃﺟﻞ ﻛﻞ ﻣﻨﻬﺞ ﺇﻓﺘﺮﺍﺿﻲ ﻟﻜﻞ ﺻﻨﻒ ﻣﺸﺘﻖ ‪ ،‬ﺣﱴ ﻟﻮ ﱂ ﻳﻜﻦ ﺍﳌﻨﻬﺞ ﻣﻬﻴﻤﻨﺎ )‪ (overridden‬ﰲ ﺍﻟﺼﻨﻒ ﺍﳌﻮﺭﺙ‬
‫‪.‬‬

‫ﺇﺳﺘﺪﻋﺎﺀﺍﺕ ﺍﳌﻨﺎﻫﺞ ﺍﻟﺪﻳﻨﺎﻣﻴﻜﻴﺔ ﺑﺎﳌﻘﺎﺑﻞ ﺗﻨﺠﺰ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺭﻗﻢ ﻓﺮﻳﺪ ﳛﺪﺩ ﺍﳌﻨﻬﺞ ‪ ،‬ﻭﻳﻜﻮﻥ ﳐﺰﻧﺎ ﰲ ﺍﻟﺼﻨﻒ ﻓﻘﻂ ﰲ ﺣﺎﻝ‬
‫ﻛﺎﻥ ﻣﻌﺮﻓﺎ ﻓﻴﺔ ﺃﺻﻼ ﺃﻭ ﻛﺎﻥ ﻣﻨﻬﺠﺎ ﻣﻬﻴﻤﻨﺎ ‪ ،‬ﺍﻟﺒﺤﺚ ﻋﻦ ﺍﳌﻨﻬﺞ ﺍﳌﻄﺎﺑﻖ ﻳﻜﻮﻥ ﻋﺎﺩﺓ ﺃﺑﻄﺄ ﻣﻦ ﺍﻟﺒﺤﺚ ﲞﻄﻮﺓ ﻭﺍﺣﺪﺓ ﰲ‬
‫ﺟﺪﻭﻝ ﺍﳌﻨﺎﻫﺞ ﺍﻹﻓﺘﺮﺍﺿﻴﺔ ﺍﻟﺴﺎﺑﻖ ‪ ،‬ﻭﺍﳌﻴﺰﺓ ﺍﻷﺳﺎﺳﻴﺔ ﻟﻪ ﺃﻥ ﺍﳌﻨﺎﻫﺞ ﺍﻟﺪﻳﻨﺎﻣﻴﻜﻴﺔ ﺗﻮﻟﺪ ﰲ ﺍﻷﺻﻨﺎﻑ ﺍﳌﺸﺘﻘﻪ ﻓﻘﻂ ﻋﻨﺪﻣﺎ ﻳﻜﻮﻥ‬
‫ﻣﻨﻬﺞ ﺍﻟﺼﻨﻒ ﺍﳌﺸﺘﻖ ﻣﻬﻴﻤﻨﺎ ‪.‬‬

‫ﻓﻜﺮﺓ ‪ :‬ﺍﳌﻨﺎﻫﺞ ﺍﳌﺘﺄﺧﺮﺓ ﺍﻟﺘﺤﺪﻳﺪ ﳝﻜﻦ ﺃﻥ ﺗﺴﺘﺨﺪﻡ ﳌﻌﺎﳉﺔ ﺭﺳﺎﺋﻞ ﻭﻳﻨﺪﻭﺯ ‪ ،‬ﻭﻫﺬﺓ ﺍﻟﺘﻘﻨﻴﺔ ﳝﻜﻦ ﺃﻥ ﺗﻜﻮﻥ ﻣﻔﻴﺪﺓ ﺟﺪﺍ‬
‫ﳌﱪﳎﻲ ﻭﻳﻨﺪﻭﺯ ﺍﻟﺬﻳﻦ ﳝﻠﻜﻮﻥ ﺍﳋﱪﺓ ﺍﻟﻜﺎﻣﻠﺔ ﺑﺮﺳﺎﺋﻞ ﻭﻳﻨﺪﻭﺯ ﻭﺗﻮﺍﺑﻊ ‪. API‬‬

‫ﻣﻼﺣﻈﺔ ‪:‬‬

‫ﻛﺬﻟﻚ ﺗﺴﺘﺨﺪﻡ ﺍﻟﻜﻠﻤﺔ ﺍﳌﻔﺘﺎﺣﻴﺔ ‪ Abstract‬ﻟﻠﺘﺼﺮﻳﺢ ﻋﻦ ﻣﻨﺎﻫﺞ ﺳﺘﻌﺮﻑ ﻓﻘﻂ ﰲ ﺍﻷﺻﻨﺎﻑ ﺍﳌﺸﺘﻘﺔ ﻣﻦ ﺍﻟﺼﻨﻒ ﺍﳊﺎﱄ ‪،‬‬
‫ﻭﺍﻟﻔﺮﻕ ﺑﻴﻨﻬﺎ ﻭﺑﲔ ﺍﳌﻨﺎﻫﺞ ﺍﻹﻓﺘﺮﺍﺿﻴﺔ ﺃﻧﻪ ﳚﺐ ﺗﻌﺮﻳﻔﻬﺎ ﰲ ﻛﻞ ﺍﻷﺻﻨﺎﻑ ﺍﳌﺸﺘﻘﺔ ‪ .‬ﻣﺜﻼ ﺇﺫﺍ ﻛﺎﻥ ﺍﻟﺼﻨﻒ ‪ Tanimal‬ﳝﻠﻚ‬
‫ﺍﳌﻨﻬﺞ ﺍﻹﻓﺘﺮﺍﺿﻲ ‪ Voice‬ﻓﺈﻥ ﺃﻱ ﺻﻨﻒ ﻣﺸﺘﻖ ﻣﻨﻪ ﳝﻜﻨﺔ ﺃﻥ ﻳﻌﺮﻑ ﻣﻨﻬﺞ ‪ Voice‬ﺧﺎﺹ ﺑﻪ ‪ ،‬ﺃﻣﺎ ﺇﺫﺍ ﻛﺎﻥ ﳝﻠﻚ ﺍﳌﻨﻬﺞ‬
‫‪ Voice‬ﻛﻤﻨﻬﺞ ﻣﺴﺘﺨﻠﺺ )‪ (Abstract‬ﻓﺈﻧﺔ ﻳﺘﻮﺟﺐ ﻋﻠﻰ ﻛﻞ ﺻﻨﻒ ﻣﺸﺘﻖ ﺇﻋﺎﺩﺓ ﺗﻌﺮﻳﻔﻪ ‪.‬‬

‫‪٣٩‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺍﳌﻌﺎﻣﻼﻥ ‪ IS‬ﻭ ‪: AS‬‬

‫ﻟﻘﺪ ﺗﻜﻠﻤﻨﺎ ﰲ ﺍﻟﻔﻘﺮﺍﺕ ﺍﻟﺴﺎﺑﻘﺔ ﻋﻦ ﺗﻮﺍﻓﻘﻴﺔ ﺍﻷﳕﺎﻁ ﰲ ﺩﻟﻔﻲ ‪ ،‬ﻭﺇﻣﻜﺎﻧﻴﺔ ﻧﺴﺐ ﺃﺻﻨﺎﻑ ﻣﺸﺘﻘﺔ ﺇﱃ ﺃﺻﻨﺎﻓﻬﺎ ﺍﳉﺬﺭ ﺑﺪﻭﻥ‬
‫ﻣﺸﺎﻛﻞ ‪ .‬ﺣﺴﻨﺎﹰ ‪..‬‬

‫ﺩﻋﻨﺎ ﻧﻔﺮﺽ ﺣﺎﻟﺔ ﺧﺎﺻﺔ ﻫﻨﺎ ‪ ،‬ﻭﻟﻴﻜﻦ ﺍﻟﺼﻨﻔﺎﻥ ‪ Tanimal‬ﻭ ‪. Tdog‬‬

‫‪Tdog‬‬ ‫ﺃﺳﺘﻄﻴﻊ ﺃﻥ ﺃﻧﺴﺐ ‪ Tdog‬ﺇﱃ ﻣﺘﺤﻮﻝ ﻣﻦ ﺍﻟﺼﻨﻒ ﺍﻷﺏ ‪ Tanimal‬ﻛﻤﺎ ﺭﺃﻳﻨﺎ ﺳﺎﺑﻘﺎ ‪ .‬ﻟﻜﻦ ﻟﻨﻔﺮﺽ ﺃﻥ ﻟﻠﺼﻨﻒ‬
‫ﻣﻨﻬﺞ ﺟﺪﻳﺪ ﻫﻮ ‪ Eat‬ﻣﺜﻼ ‪ ،‬ﺇﺫﺍ ﻗﻤﺖ ﺑﺎﻟﻨﺴﺐ ﺍﻟﺴﺎﺑﻖ ﻭﻗﺒﻞ ﺍﳌﺘﻐﲑ ﻣﻦ ﺍﻟﻨﻮﻉ ‪ Tanimal‬ﺃﻥ ﻳﺪﻝ ﻋﻠﻰ ﺍﻟﻐﺮﺽ ﻣﻦ ﺍﻟﻨﻮﻉ‬
‫‪ TDog‬ﻳﻔﺘﺮﺽ ﺃﻥ ﺃﺳﺘﻄﻴﻊ ﺇﺳﺘﺪﻋﺎﺀ ﺍﳌﻨﻬﺞ ‪ Eat‬ﺍﳋﺎﺹ ﺏ ‪ .. ، Tdog‬ﻭﻟﻜﻦ ﺫﻟﻚ ﻟﻦ ﳛﺪﺙ ﰲ ﺍﳊﻘﻴﻘﺔ ‪ ،‬ﻹﻥ ﺍﳌﺘﺤﻮﻝ‬
‫ﻻﺯﺍﻝ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ Tanimal‬ﻭﺍﻟﻌﻤﻠﻴﺔ ﺑﺮﻣﺘﻬﺎ ﻫﻲ ﺃﻥ ﺍﳌﺘﺤﻮﻝ ﻗﺒﻞ ﺃﻥ ﳛﺘﻮﻱ ﻏﺮﺽ ‪ Tdog‬ﻟﻜﻨﺔ ﻏﲑ ﻗﺎﺩﺭ ﻋﻠﻰ ﺗﻠﺒﻴﺔ ﻛﺎﻓﺔ‬
‫ﻣﺘﻄﻠﺒﺎﺕ ‪) Tdog‬ﺍﻟﻐﲑ ﻣﻮﺟﻮﺩﺓ ﰲ ‪ Tanimal‬ﺃﺻﻼ ( ‪.‬‬

‫ﳊﻞ ﻫﺬﺍ ﺍﻹﺷﻜﺎﻝ ﻧﺴﺘﻄﻴﻊ ﺇﺳﺘﺨﺪﺍﻡ ﺗﻘﻨﻴﺔ ﻣﻦ ﺗﻘﻨﻴﺎﺕ ‪ ، (run-time type information) RTTI‬ﻭﺍﻟﱵ ﺗﻌﺘﻤﺪ ﻋﻠﻰ ﻓﻜﺮﺓ‬
‫ﺃﻥ ﻛﻞ ﻏﺮﺽ ﻳﻌﺮﻑ ﻣﺎﻫﻮ ﳕﻄﺔ ﻭﻣﺎﻫﻮ ﺍﻟﺼﻨﻒ ﺍﻷﺏ ﻟﻪ ‪.‬‬

‫ﺗﺴﺘﻄﻴﻊ ﺍﻟﺴﺆﺍﻝ ﻋﻦ ﻫﺬﺓ ﺍﳌﻌﻠﻮﻣﺎﺕ ﺑﺈﺳﺘﺨﺪﺍﻡ ﺍﳌﻌﺎﻣﻞ ‪ ، IS‬ﺍﻟﺸﺒﻴﻪ ﺇﱃ ﺣﺪ ﻣﺎ ﺑﺎﳌﺴﺎﻭﺍﺓ )=( ‪ .‬ﺑﺎﺭﺍﻣﺘﺮﺍ ‪ is‬ﳘﺎ ﻏﺮﺽ ﻣﻦ‬
‫ﺍﻟﻴﺴﺎﺭ ﻭﺻﻨﻒ ﻣﻦ ﺍﻟﻴﻤﲔ ‪ ،‬ﻭﳛﺪﺩ ‪ Is‬ﺇﺫﺍ ﻛﺎﻥ ﺍﻟﻐﺮﺽ ﺍﻷﻳﺴﺮ ﻣﻦ ﺍﻟﺼﻨﻒ ﺍﻷﳝﻦ ﺃﻡ ﻻ ‪.‬‬
‫… ‪if MyAnimal is TDog then‬‬

‫ﺍﻵﻥ ﻭﺑﻌﺪ ﺃﻥ ﺗﺄﻛﺪﺕ ﺃﻥ ﺍﻟﺼﻨﻒ ﻫﻮ ‪ Tdog‬ﳝﻜﻨﻚ ﺇﺟﺮﺍﺀ ﲢﻮﻳﻞ ﺁﻣﻦ ﻟﻠﺼﻨﻒ ‪ Tanimal‬ﺇﱃ ‪ Tdog‬ﻛﺎﻵﰐ ‪:‬‬
‫‪var‬‬
‫;‪MyDog: TDog‬‬
‫‪begin‬‬
‫‪if MyAnimal is TDog then‬‬
‫‪begin‬‬
‫;)‪MyDog := TDog (MyAnimal‬‬
‫;‪Text := MyDog.Eat‬‬
‫;‪end‬‬

‫ﺑﺈﻣﻜﺎﻧﻨﺎ ﺇﳒﺎﺯ ﻧﻔﺲ ﺍﻟﻌﻤﻠﻴﺔ ﺍﻟﺴﺎﺑﻘﺔ ﺑﺎﳌﻌﺎﻣﻞ ﺍﳍﺎﻡ ﺍﻟﺜﺎﱐ ﺍﻟﺬﻱ ﺗﻮﻓﺮﺓ ﻟﻨﺎ ‪ RTTI‬ﻭﻫﻮ ﺍﳌﻌﺎﻣﻞ ‪ ، AS‬ﻭﺍﻟﺬﻱ ﻳﻘﻮﻡ ﺑﻌﻤﻠﻴﺔ‬
‫ﺍﻟﺘﺤﻮﻳﻞ ﺍﻟﺴﺎﺑﻘﺔ ﻓﻘﻂ ﺇﺫﺍ ﻛﺎﻥ ﺍﻟﺼﻨﻒ ﺍﳌﻄﻠﻮﺏ ﻣﺘﻮﺍﻓﻖ ﻣﻊ ﺍﻟﺼﻨﻒ ﺍﻷﺻﻠﻲ ‪ .‬ﺑﺎﺭﺍﻣﺘﺮﺍ ﺍﳌﻌﺎﻣﻞ ﳘﺎ ﺃﻳﻀﺎ ﻏﺮﺽ ﻳﺴﺎﺭﻱ‬
‫ﻭﺻﻨﻒ ﳝﻴﲏ ﻭﺍﻟﻨﺎﺗﺞ ﻫﻮ ﻏﺮﺽ ﰎ ﲢﻮﻳﻠﺔ ﺇﱃ ﺍﻟﺼﻨﻒ ﺍﳉﺪﻳﺪ ﺍﳌﻌﻄﻰ ‪:‬‬
‫;‪MyDog := MyAnimal as TDog‬‬
‫;‪Text := MyDog.Eat‬‬

‫‪٤٠‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺇﺫﺍ ﻛﻨﺖ ﺗﺮﻳﺪ ﻓﻘﻂ ﺇﺳﺘﺪﻋﺎﺀ ‪ Eat‬ﺑﺈﻣﻜﺎﻧﻚ ﺇﺳﺘﺨﺪﺍﻡ ﺣﺎﻟﺔ ﺃﺑﺴﻂ ‪:‬‬
‫;‪(MyAnimal as TDog).Eat‬‬

‫ﻧﺘﻴﺠﺔ ﺍﻟﺘﻌﺒﲑ ﺳﺘﻜﻮﻥ ﻏﺮﺽ ﻣﻦ ﺍﻟﺼﻨﻒ ‪ Tdog‬ﻭﺑﺈﻣﻜﺎﻧﻚ ﺇﺳﺘﺨﺪﺍﻡ ﺇﻱ ﻣﻨﻬﺞ ﻣﻦ ﻫﺬﺍ ﺍﻟﺼﻨﻒ ‪ ،‬ﺍﻟﻔﺎﺭﻕ ﺑﲔ ﺍﻟﺘﺤﻮﻳﻞ‬
‫ﺍﻟﺴﺎﺑﻖ ﻭﺍﻟﺘﺤﻮﻳﻞ ﺑﺈﺳﺘﺨﺪﺍﻡ ‪ ، as‬ﺃﻥ ‪ as‬ﺳﻴﺨﺘﱪ ﺍﻟﻐﺮﺽ ﻭﻳﺮﻓﻊ ﺇﺳﺘﺜﻨﺎﺀ ﺇﺫﺍ ﻛﺎﻥ ﺍﻟﻐﺮﺽ ﻏﲑ ﻣﺘﻮﺍﻓﻖ ﻣﻊ ﺍﻟﺼﻨﻒ ﺍﻟﺬﻱ‬
‫ﳓﺎﻭﻝ ﲢﻮﻳﻠﺔ ﺇﻟﻴﺔ ‪ ،‬ﻭﻫﺬﺍ ﺍﻹﺳﺘﺜﻨﺎﺀ ﻫﻮ )" ‪. ("EInvalidCast‬‬

‫ﺇﺫﺍ ﺃﺭﺩﺕ ﲡﻨﺐ ﺣﺪﻭﺙ ﺍﻹﺳﺘﺜﻨﺎﺀ ﺑﺈﻣﻜﺎﻧﻚ ﺇﺳﺘﺨﺪﺍﻡ ﺍﻟﻄﺮﻳﻘﺔ ﺍﻷﻭﱃ‬


‫‪if MyAnimal is TDog then‬‬
‫;‪TDog(MyAnimal).Eat‬‬

‫ﻟﻜﲏ ﻻ ﺃﺭﻯ ﺩﺍﻉ ﻹﺳﺘﺨﺪﺍﻡ ‪ is‬ﻭ ‪ as‬ﻭﺭﺍﺀ ﺑﻌﻀﻬﻤﺎ ﻭﺍﻟﻘﻴﺎﻡ ﺑﻌﻤﻠﻴﺔ ﺍﳌﻘﺎﺭﻧﺔ ﻣﺮﺗﲔ ‪.‬‬

‫ﻫﺬﺍﻥ ﺍﳌﻌﺎﻣﻼﻥ ﺃﺳﺎﺳﻴﺎﻥ ﻭ ﻣﻔﻴﺪﺍﻥ ﺟﺪﺍ ﰲ ﺩﻟﻔﻲ ‪ ،‬ﻹﻧﻚ ﻋﺎﺩﺓ ﻣﺎ ﺗﺮﻳﺪ ﻛﺘﺎﺑﺔ ﺷﻔﺮﺓ ﻋﺎﻣﺔ ﺗﺴﺘﺨﺪﻡ ﻣﻦ ﻋﺪﺓ ﻋﻨﺎﺻﺮ ﺑﻨﻔﺲ‬
‫ﺍﻟﻄﺮﻳﻘﺔ ‪.‬‬

‫ﺃﻫﻢ ﻣﺜﺎﻝ ﳜﻄﺮ ﺑﺒﺎﱄ ﻫﻮ ﺇﺳﺘﺨﺪﺍﻡ ﺍﳌﺘﺤﻮﻝ ﺍﻟﻮﺳﻴﻄﻲ ‪ Sender‬ﰲ ﻛﻞ ﺃﺣﺪﺍﺙ ﺩﻟﻔﻲ ‪ Sender ،‬ﻫﻮ ﻣﺘﺤﻮﻝ ﻣﻦ ﺍﻟﺼﻨﻒ‬
‫ﺍﳉﺪ ‪ Tobject‬ﺍﻟﺬﻱ ﻳﻘﺒﻞ ﲨﻴﻊ ﺍﻷﻏﺮﺍﺽ ‪ ،‬ﻭﺑﺎﻟﺘﺎﱄ ﺩﺍﺋﻤﺎ ﲢﺘﺎﺝ ﻟﺮﺩﺓ ﺇﱃ ﺍﻟﻐﺮﺽ ﺍﻷﺻﻠﻲ ﳌﻌﺮﻓﺔ ﻣﻦ ﻫﻮ ﻫﺬﺍ ﺍﻟﻐﺮﺽ ﺍﻟﺬﻱ‬
‫ﻃﻠﺐ ﺍﳊﺪﺙ ‪:‬‬

‫;)‪procedure TForm1.Button1Click(Sender: TObject‬‬


‫‪begin‬‬
‫‪if Sender is TButton then‬‬
‫‪...‬‬
‫;‪end‬‬

‫ﺇ‪‬ﺎ ﺗﻘﻨﻴﺔ ﺷﺎﺋﻌﺔ ﰲ ﺩﻟﻔﻲ ‪ ،‬ﻭﺗﺴﺘﺨﺪﻡ ﰲ ﻛﺜﲑ ﻣﻦ ﺍﳊﺎﻻﺕ ‪ ،‬ﻣﻌﺎﻣﻼ ﻣﻌﻠﻮﻣﺎﺕ ﳕﻂ ﺯﻣﻦ ﺍﻟﺘﺸﻐﻴﻞ ‪ RTTI‬ﻫﺬﻳﻦ ﻗﻮﻳﺎﻥ‬
‫ﻟﻠﻐﺎﻳﺔ ‪ ،‬ﻭﻳﻌﺘﱪﺍﻥ ﻣﻦ ﻃﺮﻕ ﺍﻟﱪﳎﺔ ﺍﻟﻘﻴﺎﺳﻴﺔ ﺍﻟﱵ ﺗﺘﺒﻌﻬﺎ ﺑﻮﺭﻻﻧﺪ ﰲ ﺷﻔﺮﺓ ﻋﻨﺎﺻﺮ ‪ ، VCL‬ﻭﻟﻜﻦ ﺭﻏﻢ ﺫﻟﻚ ﺗﻮﺟﺪ ﺑﻌﺾ‬
‫ﺍﳊﺎﻻﺕ ﺍﳋﺎﺻﺔ ﻟﺘﻔﻀﻴﻞ ﺇﺳﺘﺨﺪﺍﻡ ﻃﺮﻕ ﺃﺧﺮﻯ ﻋﻠﻴﻬﻤﺎ ﻋﻨﺪﻣﺎ ﺗﺮﻳﺪ ﺣﻞ ﻣﺸﻜﻠﺔ ﻣﻌﻘﺪﺓ ﺗﺴﺘﺨﺪﻡ ﺃﺻﻨﺎﻑ ﻣﺘﻨﻮﻋﺔ ﻭﻣﺘﺪﺍﺧﻠﺔ‬
‫ﺃﻧﺼﺤﻚ ﺑﺎﻟﻌﻤﻞ ﻣﻊ ﺗﻌﺪﺩﻳﺔ ﺍﻷﺷﻜﺎﻝ ‪ ،‬ﻭﺍﻟﻘﺎﻋﺪﺓ ﺍﻵﻥ ﻫﻲ ﺃﻥ ﻻ ﺗﺴﺘﺨﺪﻡ ‪ RTTI‬ﻣﻜﺎﻥ ﺗﻌﺪﺩﻳﺔ ﺍﻷﺷﻜﺎﻝ ‪،‬‬

‫ﻣﺸﻜﻠﻪ ﺍﻝ ‪ RTTI‬ﺃ‪‬ﺎ ﳚﺐ ﺃﻥ ﺗﺴﲑ ﰲ ﺍﻟﺸﺠﺮﺓ ﺍﻟﻮﺭﺍﺛﻴﺔ ﻟﻠﺘﺄﻛﺪ ﻣﻦ ﺃﻥ ﺍﻟﺼﻨﻒ ﻣﻄﺎﺑﻖ ‪ .‬ﺭﲟﺎ ﻳﺴﺒﺐ ﺫﻟﻚ ﺃﺛﺮﺍ ﺳﻴﺌﺎ ﻟﻸﺩﺍﺀ‬

‫‪٤١‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺇﺳﺘﺨﺪﺍﻡ ﺍﻟﻮﺍﺟﻬﺎﺕ ‪: Using Interfaces‬‬

‫ﺗﻜﻤﻦ ﺃﳘﻴﺔ ﺍﻟﻮﺍﺟﻬﺎﺕ ﰲ ﺗﻘﺪﱘ ﺑﻌﺾ ﻣﻴﺰﺍﺕ ﺍﻟﻮﺭﺍﺛﺔ ﺍﳌﺘﻌﺪﺩﺓ )‪ (multiple inheritance‬ﺑﺴﻬﻮﻟﺔ ﻭﺑﺪﻭﻥ ﺍﻟﻐﺮﻕ ﰲ‬
‫ﺍﻟﺘﻔﺼﻴﻼﺕ ﺍﻟﻨﺤﻮﻳﺔ ﳍﺎ ‪ ،‬ﻛﻤﺎ ﺃﻥ ﻟﻠﻮﺍﺟﻬﺎﺕ ﺃﳘﻴﺔ ﺃﺳﺎﺳﻴﺔ ﻣﻦ ﺃﺟﻞ ﺇﺳﺘﺨﺪﺍﻡ ﳕﺎﺫﺝ ﺍﻷﻏﺮﺍﺽ ﺍﳌﻮﺯ‪‬ﻋﺔ )ﻣﺜﻞ ‪ CORBA‬ﻭ‬
‫‪ (SOAP‬ﻭﺍﻟﺘﻔﺎﻋﻞ ﻣﻊ ﺃﻏﺮﺍﺽ ﲤﺖ ﻛﺘﺎﺑﺘﻬﺎ ﰲ ﻟﻐﺎﺕ ﺃﺧﺮﻯ ‪ C++‬ﺃﻭ ‪ Java‬ﻣﺜﻼ ‪.‬‬

‫ﻣﻌﻈﻢ ﺍﻟﻠﻐﺎﺕ ﺍﻟﻐﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﺔ ﺍﳊﺪﻳﺜﺔ ‪ ،‬ﻣﻦ ‪ Java‬ﺣﱴ ‪ ، C#‬ﲤﻠﻚ ﻓﻜﺮﺓ ﺍﻟﻮﺍﺟﻬﺎﺕ ﻫﺬﺓ ‪.‬‬

‫ﺇﺫﺍ ﻗﻤﺖ ﺑﺘﻌﺮﻳﻒ ﺻﻨﻒ ﺟﺪﻳﺪ ﻣﻦ ﺃﺟﻞ ﲤﺜﻴﻞ ﺻﻨﻒ ﺁﺧﺮ ﺑﺸﻜﻞ ﳐﺘﺼﺮ ‪ ،‬ﳝﻜﻦ ﳍﺬﺍ ﺍﻹﺧﺘﺼﺎﺭ ﺃﻥ ﻳﺼﻞ ﺇﱃ ﺩﺭﺟﺔ ﺃﻥ‬
‫ﺍﻟﺼﻨﻒ ﻳﻘﻮﻡ ﺑﺴﺮﺩ ﳎﻤﻮﻋﺔ ﻣﻦ ﺍﳌﻨﺎﻫﺞ ﻓﻘﻂ ﺣﱴ ﺑﺪﻭﻥ ﺗﻌﺮﻳﻒ ﻹﺟﺴﺎﻡ ﻫﺬﺓ ﺍﳌﻨﺎﻫﺞ ﰲ ﻗﺴﻢ ‪، Implementation‬‬

‫ﰲ ﻫﺬﻩ ﺍﳊﺎﻟﺔ ﳝﻜﻨﻚ ﺇﺳﺘﺨﺪﺍﻡ ﺗﻘﻨﻴﺔ ﺍﻟﻮﺍﺟﻬﺎﺕ ‪ ، Interfaces‬ﻭﻛﺄﻧﻨﺎ ﻧﻌﱪ ﻋﻦ ﻫﺬﺍ ﺍﻟﺼﻨﻒ ﺍﳌﺨﺘﺼﺮ ﺑﻮﺍﺟﻬﺔ ﲢﻮﻱ ﺗﻌﺮﻳﻒ‬
‫ﻹﲰﺎﺀ ﺍﳌﻨﺎﻫﺞ ﺍﻟﱵ ﳝﻜﻦ ﺇﺳﺘﺨﺪﺍﻣﻬﺎ ‪.‬‬

‫‪ -‬ﺍﻷﻏﺮﺍﺽ ﻣﻦ ﺍﻟﻨﻤﻂ ﻭﺍﺟﻬﺔ ﲢﺮﺭ ﺗﻠﻘﺎﺋﻴﺎ ﻋﻨﺪ ﺇﻧﺘﻬﺎﺀ ﺍﻟﺼﻼﺕ ﻣﻌﻬﺎ ‪ ،‬ﺑﺸﻜﻞ ﻣﺸﺎﺑﻪ ﳌﻌﺎﳉﺔ ﺍﻟﺴﻼﺳﻞ ﺍﻟﻄﻮﻳﻠﺔ ﺣﻴﺚ‬
‫ﺗﻘﻮﻡ ﺩﻟﻔﻲ ﺑﺈﺩﺍﺭﺓ ﺍﻟﺬﺍﻛﺮﺓ ﺑﺎﻟﻜﺎﻣﻞ ﺗﻘﺮﻳﺒﺎ ‪.‬‬

‫‪ -‬ﻣﻊ ﺃﻥ ﺍﻟﺼﻨﻒ ﳝﻜﻦ ﺃﻥ ﻳﺮﺙ ﺻﻨﻔﺎ ﺃﺳﺎﺳﻴﺎ ﻭﺍﺣﺪﺍ ﻓﻘﻂ ‪ ،‬ﻟﻜﻨﺔ ﳝﻜﻦ ﺃﻥ ﳝﺜﻞ ﺃﻛﺜﺮ ﻣﻦ ﻭﺍﺟﻬﻪ ﻣﻌﺎ ‪.‬‬

‫‪Iinterface‬‬ ‫‪ -‬ﻛﻤﺎ ﺃﻥ ﻛﻞ ﺍﻷﺻﻨﺎﻑ ﺗﻨﺤﺪﺭ ﻣﻦ ﺍﻟﺴﻠﻒ ‪ ، Tobject‬ﻛﺬﻟﻚ ﺗﻨﺤﺪﺭ ﻛﻞ ﺍﻟﻮﺍﺟﻬﺎﺕ ﻣﻦ ﺍﻟﺴﻠﻒ‬


‫ﻣﺘﺒﻌﺔ ﺷﺠﺮﺓ ﻭﺭﺍﺛﻴﺔ ﻣﺴﺘﻘﻠﻪ ‪.‬‬

‫‪٤٢‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﻳﺘﻢ ﺗﻌﺮﻳﻒ ﺍﻟﻮﺍﺟﻬﺎﺕ ﺑﺎﻟﺸﻜﻞ ﺍﻟﻌﺎﻡ ﺍﻟﺘﺎﱄ ‪:‬‬


‫)‪type interfaceName = interface (ancestorInterface‬‬

‫]'}‪['{GUID‬‬

‫‪memberList‬‬

‫;‪end‬‬

‫ﻣﺜﻼ ‪:‬‬
‫‪type‬‬
‫‪ICanFly = interface‬‬
‫]'}‪['{EAD9C4B4-E1C5-4CF4-9FA0-3B812C880A21‬‬
‫;‪function Fly: string‬‬
‫;‪end‬‬

‫ﺣﻴﺚ ﺃﻥ ﺗﻌﺮﻳﻒ ﻛﻞ ﻣﻦ )‪ (ancestorInterface‬ﻭ ]'}‪ ['{GUID‬ﺧﻴﺎﺭﻱ ﺣﺴﺐ ﺍﳊﺎﻟﺔ ‪.‬‬

‫‪ ancestorInterface‬ﻫﻮ ﺍﳉﺪ ﺍﻟﺬﻱ ﺳﻨﻮﺭﺙ ﻋﻨﺔ ﺻﻨﻔﻨﺎ ‪.‬‬

‫‪ GUID‬ﺇﺧﺘﺼﺎﺭ ﻟـ)‪ (Globally Unique Identifier‬ﻫﻮ ﺭﻗﻢ ﻣﻌﺮﻑ ﻳﺴﺘﺨﺪﻡ ﻟﺘﻌﺮﻳﻒ ﺍﻟﻮﺍﺟﻬﺔ ﺑﺸﻜﻞ ﻓﺮﻳﺪ ‪.‬‬
‫ﺗﺴﺘﻄﻴﻊ ﺗﻌﺮﻳﻒ ﻫﺬﺍ ﺍﻟﺮﻗﻢ ﺗﻠﻘﺎﺋﻴﺎ ﺑﻀﻐﻂ ‪ Ctrl+Shift+G‬ﰲ ﳏﺮﺭ ﺩﻟﻔﻲ ‪.‬‬

‫ﻛﻤﺎ ﺗﻼﺣﻆ ﻓﺈﻥ ﺗﻌﺮﻳﻒ ﺍﻟﻮﺍﺟﻬﻪ ﺷﺒﻴﺔ ﺑﺘﻌﺮﻳﻒ ﺍﻟﺼﻨﻒ ﰲ ﻛﺜﲑ ﻣﻦ ﺍﳊﺎﻻﺕ ‪ ،‬ﻭﻟﻜﻦ ﺗﻮﺟﺪ ﺑﻌﺾ ﺍﻟﻔﺮﻭﻗﺎﺕ ﻟﻮﺿﻌﻬﺎ‬
‫ﰲ ﺍﳊﺴﺒﺎﻥ ‪:‬‬

‫‪ -‬ﻗﺎﺋﻤﺔ ﺍﻟﻌﻨﺎﺻﺮ )ﺍﻟﱵ ﲰﻴﻨﺎﻫﺎ ‪ memberList‬ﰲ ﺍﻟﺸﻜﻞ ﺍﻟﻌﺎﻡ ﻟﻠﺘﻌﺮﻳﻒ( ﳝﻜﻦ ﺃﻥ ﲢﻮﻱ ﻓﻘﻂ ﺇﻣﺎ ﻣﻨﺎﻫﺞ ﺃﻭ ﺧﺼﺎﺋﺺ‬
‫‪ .‬ﺗﻌﺮﻳﻒ ﺣﻘﻮﻝ ﻏﲑ ﻣﺴﻤﻮﺡ ﺑﻪ ﰲ ﺍﻟﻮﺍﺟﻬﺎﺕ ‪.‬‬

‫‪ -‬ﲟﺎ ﺃﻧﻪ ﻻﺗﻮﺟﺪ ﻟﻠﻮﺍﺟﻬﻪ ﺣﻘﻮﻝ ‪ ،‬ﻓﺈﻥ ﳏﺪﺩﺍﺕ ‪ Read‬ﻭ ‪ Write‬ﺍﳋﺎﺻﺘﺎﻥ ﺑﺘﻌﺮﻳﻒ ﺍﳋﺼﺎﺋﺺ ﳚﺐ ﺃﻥ ﻳﻜﻮﻧﺎ‬
‫ﻣﻨﺎﻫﺞ ﺣﺘﻤﺎ ‪.‬‬

‫‪ -‬ﻛﻞ ﻋﻨﺎﺻﺮ ﺍﻟﻮﺍﺟﻬﺔ ﺗﻜﻮﻥ ﻋﺎﻣﺔ )‪ ، (Public‬ﻭﻻ ﳎﺎﻝ ﻟﺘﻘﻴﻴﺪ ﺍﻟﺮﺅﻳﺎ ‪.‬‬

‫‪ -‬ﻟﻴﺲ ﻟﻠﻮﺍﺟﻬﺔ ﺑﺎﱐ ﺃﻭ ﻫﺎﺩﻡ )‪ (constructors or destructors‬ﻳﻌﺮﻓﺎﻥ ﺿﻤﻨﻬﺎ ‪.‬‬

‫‪٤٣‬‬
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

:‫ﻭﻫﺬﺍ ﻣﺜﺎﻝ ﻋﻠﻰ ﺗﻌﺮﻳﻒ ﻭﺍﺟﻬﺔ ﻣﺄﺧﻮﺫ ﻣﻦ ﺩﻟﻔﻲ‬


type

IMalloc = interface(IInterface)

['{00000002-0000-0000-C000-000000000046}']

function Alloc(Size: Integer): Pointer; stdcall;

function Realloc(P: Pointer; Size: Integer): Pointer; stdcall;

procedure Free(P: Pointer); stdcall;

function GetSize(P: Pointer): Integer; stdcall;

function DidAlloc(P: Pointer): Integer; stdcall;

procedure HeapMinimize; stdcall;

end;

. ‫ﻭﺑﻌﺪﻣﺎ ﺗﻘﻮﻡ ﺑﺘﻌﺮﻳﻒ ﺍﻟﻮﺍﺟﻬﺔ ﺗﺴﺘﻄﻴﻊ ﺗﻌﺮﻳﻒ ﺻﻨﻒ ﻣﻦ ﺃﺟﻞ ﺇﺳﺘﺨﺪﺍﻣﻬﺎ ﺑﻮﺍﺳﺘﻄﺔ‬

: ‫ﻣﺜﻼ‬
type
TAirplane = class (TInterfacedObject, ICanFly)
function Fly: string;
end;

‫ ﻃﺮﻳﻘﺔ ﺍﻹﺳﺘﺨﺪﺍﻡ ﻫﻲ ﻧﻔﺴﻬﺎ ﻹﻧﻨﺎ ﻧﺘﻌﺎﻣﻞ‬، ‫ﺍﻵﻥ ﺃﺻﺒﺤﻨﺎ ﺟﺎﻫﺰﻳﻦ ﻹﺳﺘﺨﺪﺍﻡ ﻏﺮﺽ ﻣﻦ ﻫﺬﺍ ﺍﻟﺼﻨﻒ ﺍﻟﺬﻱ ﳝﺜﻞ ﺍﻟﻮﺍﺟﻬﺔ‬
: ‫ﻣﻊ ﺻﻨﻒ ﻣﻦ ﺍﻟﻮﺍﺟﻬﺔ ﻭﻟﻴﺲ ﻣﻊ ﺍﻟﻮﺍﺟﻬﺔ ﻣﺒﺎﺷﺮﺓ‬
var
Flyer1: ICanFly;
begin
Flyer1 := TAirplane.Create;
Flyer1.Fly;
end;

٤٤
‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬ ‫ﺍﻟﱪﳎﺔ ﺍﻟﻐﺮﺿﻴـﺔ ﺍﻟﺘﻮﺟﻪ ﰲ ﺩﻟﻔﻲ‬

‫ﺭﺅﻳـﻪ ﻭﺇﻋﺪﺍﺩ ‪:‬‬


‫ﻋﺮﻭﺓ ﻋﻴﺴﻰ‬

‫ﺍﳌﺮﺍﺟﻊ ‪:‬‬
‫‪ Mastring Delphi‬ﻟﻠﻤﺆﻟﻒ ‪Marco Cantu‬‬

‫‪Orwah Ali Essa .. Syria 2004-2005‬‬ ‫‪.‬‬ ‫‪ww.orwah.net‬‬


‫‪٤٥‬‬

You might also like