C++ Idioms | Attorney Client Idiom - 1


C++ için önemli idiomlardan biri de Attorney Client Idiom olarak isimlendirilen idiomdur. Temel olarak nesne yönelimli programlamanın önemli ilkelerinden birisi olan encapsulation'ı bozabilecek durumları ortadan kaldırmak için geliştirilmistir. Encapsulation ilkesinin temeli verinin bütünlüğünü bozabilecek tüm fonksiyonların veya üyelerinin dışarıdan erişime kapalı olmasını sağlamak üzerinedir. Bunun icin sınıfın private bölümü kullanılmaktadır. Bu sayede sınıfın dışarıya sunduğu interface ile implementation kısmı birbirinden ayrılmış olmaktadır. Fakat hayatta her şey siyah/beyaz olmadığı gibi burada da benzer bir durum vardır. Bazen sınıfın private bölümüne sınıfın kendi kodlarının dışında dışarıdan erişilebilmesi durumu bazı problemler için en iyi çözüm haline gelebilmektedir. Bunun için C++ dilinin bize sunduğu friend'lik kavramı üzerinden bu sağlanabilmektedir. C++ 'da bir sınıf bir global işleve, başka bir sınıfın bir üye işlevine ya da başka bir sınıfın tüm işlevlerine bir arkadaşlık (friend) bildirimi ile, kendi private bölümüne erişim hakkı vermektedir. C++’ta friend bildirimiyle, yalnızca sınıfın belirli private öğelerine erişim hakkı vermek gibi bir özellik şimdilik mümkün değil. Eğer bir sınıfa arkadaşlık verirseniz sınıfınızın tüm private öğelerini o sınıfın erişimine açmış oluyoruz. Peki biz bu problemi nasil aşacağız? Ayrıca friend'lik iki sınıf arasındaki bağımlılığı (coupling) arttıran bir durum. Bu da SOLID prensiplerine uymayan bir durum. Sınıfınızın private bölümünde değişiklik yaptığınızda arkadaşlık verdiğiniz sınıfların kodlarında da bakım/değişiklik yapılması gerekmetedir. Bu da istenmeyen bir durumdur. Arkadaşlık vermek en makul çözümse olabilse de bu noktada coupling'i azaltmak için sınıfın private öğelerinin tümünü erişime açmak yerine yalnızca bu ihtiyaca konu private öğeleri erişime açmak daha iyi bir çözüm olacaktir. Bunun için C++ dünyasında kullanılan çözüm iki sınıf arasında bir 3. sınıf oluşturmak ve iki sınıf arasındaki ilişkiyi bu 3. sınıf üzerinden yapmak olacaktir. Iste bu noktada kabul gören çözüm olan Attorney Client Idiyom 'unun nasıl yapıldığına geçmek en mantıklısı olacaktır.


Yukarıdaki örnek için Engine sınıfının m_id ve m_hashValue olarak iki üye elemanı bulunmakta ve bir nedenle bunlardan sadece birini dışarıya açmak istemekteyiz. Bu noktada friend' lik vermek dışında başka bir çözümümüz bulunmadığını düşünelim. Işte bu durumda yukarıdaki gibi vekil bir sınıf (CarAttorney) yaratıp Engine sınıfın friend 'liğini bu sınıfa vererek, gerçek sınıfa ise friendliği bu vekil sınıftan verilerek arada bir katman oluşturulur. Ve hedeflenen sınıf sadece bizim CarAttorney sınıfında implemente ettiğimiz static işlevler dışında verinin bütünlüğünü bozacak hiç bir duruma izin verilmemiş olur.


Arkadaşlık bildirimleri taban sınıflardan kalıtım yoluyla türemiş sınıflara geçmez. Bu ne demek? Taban sınıfın arkadaşlık verdiği Helper sınıfı yukarıdaki örnekte CarAttorney sınıfı türemiş sınıfın (V6Engine) private bölümüne erişmesi mümkün değildir. Ancak taban sınıf tarafından arkadaşlık verilen bir sınıf, taban sınıfın private bölümünde bildirilen bir virtual işlevi taban sınıf göstericisi/referansı ile çağırdığında, dynamic polymorphism gereği türemiş sınıfın virtual işlevinin çağrılması mümkündür. Bu sayede yukarıdaki örnekte BMW sınıfının printHashValue fonksiyonu CarAttorney sınıfı üzerinden yapılan çağrıda türemiş sınıfın ilgili fonksiyonuna doğrudan erişim yetkisi olmamasına rağmen CarAttorney tarafından çağrılacaktır.