29 Kasım 2022 Salı

Repository ve UnitOfWork

 DBContext
Veritabanına karşılık gelen obje yapısıdır. İçerisinde tablo yapısına karşılık gelen DbSet objeleri bulundurur. DbContext Kullanarak Tablo ve Viewlara erişebiliriz.

Repository Pattern
-Veri işlem ve sorgulamaların merkezi bir yapıya çekilmesidir. Bu sayede veritabanı işlemlerimizi tekrarlı olarak iş katmanı içinde yazmak durumunda kalmamış olacağız. 
-Buna ek olarak Veri katmanı ve bu katmanı kullanan iş katmanı arasında bir arabirim olarak yer alır ve bu iki katman arasında soyutlama görevini de üstlenmiş olur.

UnitOfWork
-Bu pattern, iş katmanında yapılan her değişikliğin anlık olarak database e yansıması yerine, işlemlerin toplu halde tek bir connection üzerinden gerçekleşmesini sağlar.

-Unit Of Work, toplu veritabanı işlemlerini tek seferde bir kereye mahsus execute eden ve böylece bu toplu işlem neticesinde kaç kayıtın etkilendiğini rapor olarak sunabilen bir tasarım desenidir.


It is a single transaction that involves multiple CRUD operations.

When using Repository Pattern, we access the DBContext in our repositories.

Each repository generates and maintains its instance of DBContext.

This might lead to issues since DbContext has its in-memory list of records for the entities being modified or added in a single transaction.

In such cases, when SaveChanges() fails for a repository and succeeds in the other one, it will result in database inconsistency.

To avoid this, we add a Unit of Work layer that is a centralized store for all the repositories to receive the same instance of DbContext.

UoW ensures that the operations either succeed or fail as a whole.

We omit the Rollback() method in the Unit of Work implementation, leveraging EF Core's behavior that changes persist only when calling SaveChanges().




En soldaki kısım  repository kullanılmadığı durumlarda doğrudan veritabanına DbContext aracılığı ile erişilmesini göstermektedir. Sağdaki kısım ise Unit Of Work pattern kullanılarak katmanlarla ayrılan Entity Framework ve Controller bölümlerinin arasına istenildiği anda gerçek repository değil de  bir mock repository yerleştirme sayesinde test edilebilirliğin kolaylaşması sağlanmaktadır.

Entity Framework ORM(Object Relational Mapping) araçlarından biridir. ORM nedir dersek: İlişkisel veritabanı ile nesneye yönelik programlama(OOP) arasında bir köprü görevi gören araçtır. Bu köprü, ilişkisel veritabanındaki bilgilerimizi yönetmek için nesne modellerimizi kullandığımız bir yapıdır. Kısaca veritabanına bizim nesnelerimizi bağlayan ve bizim için veri alışverişini yapan Microsoft tarafından geliştirilmiş bir framework’tür.

referanslar:

21 Kasım 2022 Pazartesi

Transactional Outbox Pattern


Outbox patterni kullanarak Domain Eventleri nasıl pushlayacağımızı öğreneceğiz. Outbox Pattern transactionumuzun Atomik bir şekilde tamamlanmasını garanti etmek istediğimiz senaryolarda faydalıdır.

Problem

Event Driven Arthitecture, Loose Coupling servisler geliştirmek için kullandığımız yöntemlerden birisidir. Sistemde yapılan değişikliklerin events şeklinde ortak bir platforma, bir Message Brokera , yayımlanıplanıp oradanda  farklı consumerler tarafından handle edilmesi üzerine kuruludur.

örn. X servisindeki bir işlem, Y servisini çağıracağına (http request), yaptığı işlemi message brokera yayımladıktan sonra, bu evente abone olan Y servisi, eventi yakalayıp handle ediyor. Bu sayede bu iki servisin bir birine olan bağımlılığını ortadan kaldırmış oluyoruz.

Yukarıdaki senaryoda X servisi kendi işlerini tamamlayıp daha sonra Y nin kendi işlerini yapması için gerekli olan eventi, message brokera yollayamazsa(message broker servisi ayakta olmayabilir) burada sorun ortaya çıkıyor. Veri bütünlüğü sağlanamamış oluyor.

Çözüm

-İşte tam da bu durumda outbox pattern devreye giriyor ve X servisinin yapacağı işlem ve göndereceği event bir transactional bütünlük içerisinde gerçekleşiyor.
-Eğer event gönderilirken bir sorun ile karşılaşılırsa tüm işlem geri alınıyor. Bu sayede veri bütünlüğü sağlanmış oluyor.
-Ayrıca artık X servisinin eventi yayınlayacağı platforma olan bağımlılığı da ortadan kaldırılmış oluyor. Message Brokerin ayakta olup olmaması artık X servisini ilgilendirmiyor.
-X servisi gerekli veri tabanı işlemlerini tamamladıktan sonra direkt olarak message broker ile iletişime geçmek yerine eventlerin tutulduğu başka bir tabloya kayıt atıyor. Bu şekilde X servisi tüm bu işlemleri transactional bütünlükle yapabiliyor.
-Son olarak da bir message relay(worker service) tabloaya yazılmış olan bu eventleri alıp message brokera yolluyor. Eğer message brokera eventler başarılı bir şekilde gönderilmişse bu tablodaki eventlerin statuleri güncelleniyor.



-Diyelim ki REST Api'mize order requesti geldi. 
-İlk olarak apimiz bu isteği alıp Entity tablosuna yazacak.
-Daha sonra Outbox tablosuna kayıt atacak.
-Publisher, Outbox tablosundaki gönderilmemiş statudeki eventleri çekip bu eventleri Event Bus'a gönderecektir.
-Daha sonra Publisher, Event Bus'a gönderdiği kayıtları Outbox tablosundan silecektir. Tamda bu aşamada bir problem çıkarsa ve publisher event busa kayıtları gönderir fakat outbox tablosundan kayıtları silemezse, publisher servisi aynı kayıtları Event busa tekrar göndermiş olacaktır. Artık event busa aynı kayıt iki kez gönderilmiş olacak ve consumer aynı mesajı iki kez almış olacak. Burada oluşan dublicate kayıt sorununu nasıl çözebiliriz ?

Handling Dublicate Messages(Idempotent Consumer)

Dublicate olan messageleri handle etmek için daha önce process ettiğimizi bir tabloya kaydetmemiz gerekir. Consumer ve messageId değeri bir tabloda tutulmalıdır.

18 Kasım 2022 Cuma

Memento Pattern

Sarmalamayı bozmadan bir nesnenin iç durumunu yakala ve dışarıya çıkar öyleki nesne bu duruma daha sonra dönebilsin.

Problem

-Bazen bir nesnenin durumunu kaydetme ihtiyacı duyulur.
-Özellikle bir nesnenin durumu sıklıkla değişiyor ve zaman zaman bu değişiklikleri geri almak(undo) yada geçmişteki bir noktaya dönmek.(checkpoint)
-söz konusu ise bu ihtiyaç çok daha açık hale gelir.

Çözüm

-Memento bir nesnedir ve durumu saklanacak nesnenin bir andaki(snapshot) durumu için muhafızlık yapar.
-Memento,gerektiğinde durumu değişen nesnenin durumunu sakladığı hale geri getirmek için kullanılır.
-Memento, nesnenin sadece durumu saklanma ihtiyacı duyulan kısmını gereken derinlikte saklar

Template Method Pattern

- Bir algoritmanın ana yapısını, bazı adımlarını alt sınıflara bırakarak bir fonksiyonda tanımla.
- Template Method, Bir algoritmanın yapısını değiştirmeden bazı adımlarının alt sınıflarda tekrar tanımlanmasına imkan sağlar.

Sonuçlar
-Template method ile bir algoritmanın değişken noktaları soyutlanır.
-Template Method kalıbıyla algoritmalar arasındaki ortak noktalar bir üst sınıfta soyutlanır değişen noktalar ise alt sınıflarda yerine getirilir.
-Base classta metodları yaz alt sınıfların override etmesi gereken metotları abstract olarak tanımla. Bu base yani template clası implement eden alt sınıflar bu abstract metotların içini doldursun


Template method kalıbı Strategy kalıbı ile karıştırılabilir.

-Aralarındaki en temel fark Strategy'de tüm algoritma detayını alt sınıflara bırakılmasına karşın Template method'ta algoritmanın iskeleti ve belki bazı adımları belirlenmekte ve diğer bazı adımları alt sınıflara bırakılmaktadır.
-Strategy'de algoritma belli değildir. Template Methodda ise bazı adımlarının detayı dışında algoritma bellidir.

Strategy Design Pattern‘i davranışın tamamen değiştiği durumlarda,
Template Method Design Pattern’i ise davranışın bir kısmı değiştiği durumlarda kullanılır.

Burada dikkat etmemiz gereken nokta, Strategy Design Pattern ile fazladan aynı işi yapacak olan algoritmik çalışma gerçekleştirmektense, var olan kod parçalarının yeniden kullanılabilirliğinin arttırılmasında(Code Reusability) da tercih edildiği görülmektedir.

Yani Strategy ile yazılmış kodu refactoring yaparak template metoda dönüşebiliriz

Strategy Pattern

 Problem
-Bir dizi algoritmamızın olduğunu ve bu algoritmaları context sınıfı içerisinde Switch yada İF-ELSE bloklarıyla implemente ettiğimizi düşünelim.
örn : 18 yaşından küçükse şöyle hesapla, 18 yaşından büyükse böyle hesapla 0 ile 10 arasındaysa böyle yap, 50 ile 1000 arasında şöyle yap, 100 den büyükse şöyle yap

-Eklenecek her yeni algoritma context sınıfımız içerisine ayrı bir blok olarak eklenir. Bu da context sınıfımızın büyümesine sebep olur.
-Öte yandan algoritmalar genellikle geliştirme ve yeniden kullanım sırasında genişletilir, Optimize edilir ve değiştirilir. Bu nedenle kodumuz SOLİD'in SRP preinsibini ve OCP yi ihlal eder. Çünkü her bir Swich Case yada İF-ELSE bloğu kodumuzu değiştirmek için ayrı bir nedene karşılık gelmektedir.
-Yukarıdaki resimdeki şekilde kodumuz compile-time da belli bir algoritmaya bağlanır ve artık bu algoritmayı run-timeda değiştirmemiz imkansız hale gelir.

Çözüm
Bir algoritma ailesi tanımla, algoritmaların her birini sarmala ve onları birbirleri yerine geçebilecek hale getir.
Strateji, algoritmanın onu kullanan istemcilerden bağımsız olarak değişebilmesini sağlar.


Sonuç
Ne zaman bir şeyi hesaplamanın farklı yollarıyla karşılaşırsanız, bir iş kuralının bir faktöre göre değişem şekilleri vs. varsa Strategy kalıbını kullanın.

17 Kasım 2022 Perşembe

Mediator Pattern

 Problem


Class1 ve Class2 olmak üzere iki clasımız olsun ve bu classlarlar birbirleriyle haberleşsin.

Yukarıda ki gibi bir iletişim de;
  • Nesneler bir birine sıkı bir şekilde bağlanmıştır.
  • Her nesne başka nesnelerle iletişim kurmak istediğinde tüm nesnelerin referanslarını tutması gerekir. Böyle bir durumda kodu kontrol etmeyi zorlaştırır.
Örnek Cep telefonuyla SMS göndermek için kullanıcılar arasında iletişim kurmak için her kullanıcının kendi aralarındaki bağlantıyı tutması gerekir. Bu da hem karmaşık hemde bu referansları tutmak için kaynak ve yer ihtiyacı doğurur. CPU yu azaltır.

Çözüm
-Buradaki sorun nesnelerin sıkı bir şekilde birbiriyle etkileşime geçmesidir. Nesneler arası iletişimi yönetmek için merkezi bir nesne oluşturmamız gerekiyor.
-İşte Mediator Patternin amacı, Bir dizi nesnenin nasıl etkileşime girdiğini kapsayan ve birbirine olan bağımlılıklarını azaltan bir merkezi nesne tanımlamaktadır.
-Mediator, Nesneleri birbirine doğrudan ulaşmaktan alıkoyarak gevşek bağımlığa destek verir ve aralarındaki iletişimi serbestçe değiştirmeye izin verir.



Sonuçlar
-Mediator kalıbıyla many-to-many ilişkiler, one-to-many ye dönüşür.
-Nesnelere dağıtılacak haberleşme protokolü bilgisi merkezi olarak mediator nesnesinde toplanır.
-Böylece kontrol merkezileşir ve nesneler arası gevşek bağımlılık oluşur.

Command Pattern

 Problem


-Yukarıda ki örnekte Invoker sınıfı receiver.DoAction() requesti doğrudan uygulanıyor.
-Bu durum  run-time da bir request belirtmeyi imkansız hale getirir.
-Reusable object tasarlarken, belirli requestler compile-time da bilinmez ve run-time da belirtilmelidir.


Çözüm
-Invoker ve Receiver sınıfları arasındaki bağımlılığı azaltmak ve requesti nesne olarak ifade etmek istediğimiz de command paterne başvurabiliriz.
-Command nesneleri, isteği metot olarak soyutlamak yerine daha yetkin bir şekilde sınıf olarak soyutlayan nesnelerdir.


Ne zaman kullanılır ? 
-receiver.DoAction() metodu çağırıldığı anda işlevi yerine getirir. Bazen işlevi hemen yürütmek istemeyebiliriz. Bir kuyruğa yazılarak ayrı olarak yapılmasını istediğimiz işlerde command patterni kullanabiliriz.
- Command nesneleri bir kuyruğa yazılabilir ve muhtemelen farklı bilgisayarlarda çalışan birden çok invoker nesnesi tarafından handle edilebilir.
-Command Pattern, Command objelerini bir queue da saklamamıza izin verir. Bu şekilde redo ve undo işlemlerini uygulayabiliriz.

örnek
Bir banka uygulaması yazıyoruz ve burada deposit, witdraw ve transfer işlemleri yapılabiliyor olacak.
Bu metotlar çağırıldıkları anda bakiyeyi değiştiren para yatırma ve para çekme işlevlerine sahiptirler.
Bazen işlevleri hemen yürütmek istemeyebiliriz.
Bir kuyruğa yazılarak ayrı olarak yapılmasını istediğimiz işlerde Command Patterni kullanabiliriz.
Command Nesneleri bir kuruğa eklenebilir ve muhtemelen farklı bilgisayarlarda çalışan birden çok Invoker nesnesi tarafından handle edilebilir.
Bu programı daha scalable hale getirmenin bir yoludur.
Burada deposit ve witdraw metodları Account sınıfın içerisine eklenmiştir.

Observer Pattern

Problem




Zaman zaman bir nesnenin durumundaki değişiklikleri takip etmek ve onlardan haberdar olmak isteriz.
Subject1 nesnesinin Dependent1 ve Dependent2 isminde bağımlılıklarının olduğunu düşünelim. Subject1'in durumu değiştiğinde bu Dependent1 ve Dependent2 haberdar edilmelidir.
-Bunu yapmanın bir yolu belli aralıklarla nesnenin durumunu sorgulamaktır.
-Bu yaklaşım hem etkili değildir çünkü gereksiz yere devamlı sorgulama gerektirir hem de değişikliklerden anında haberdar olunamaz bir gecikme yaşanır.

Çözüm
Nesneler arasında bire-çoklu bir bağımlılık tanımla öyle ki bir nesnenin durumunda değişiklik olduğunda tüm bağımlı nesneler haberdar edilsin ve otomatik olarak güncellensin.


Chain Of Responsibility

Problem
Client tarafından gönderilen bir requestin potansiyel olarak birden çok handlerdan hangisinin handle edeceğine karar vermemiz gerektiğini varsayalım.

Çözüm
-Bu handlerların hepsini bir pipeline içinde encapsule edelim. 
-İstemci, işlenmesini istediği bilgiyi bu zincirin en başında yer alan nesneye gönderir.
-Zincir içerisinde yer alan nesne örnekleride söz konusu içeriği asıl işleneceği yere kadar göndererirler.

-Ortak bir mesaj veya talebin(Request), birbirlerine zayıf bir şekilde bağlanmış(Loosly Coupled) nesneler arasında gezdirilmesi ve bu zincir içerisinde asıl sorumlu olanı tarafından ele alınması gerektiği vakalarda kullanılmaktadır.



-CoR bir amaca yönelik bir dizi işlemi gerçekleştiren nesnelerin birbirlerinden bağımsız bir şekilde çalışmasını ve her bir nesnenin sadece kendisine tanımlı işleri yapmasını sağlayan bir design patterindır. Sorumluluk zinciri ismi de burdan gelmektedir.
-Bu nesneler arasındaki tek bağlantı mesaj(request) yapısıdır. Bütün nesneler bu mesaj yapısını kullanarak işlerini gerçekleştirir.
-Bu nesneler, çalışma yapısı olarak aynı işi yapmalarına rağmen birbirlerinden haberdar olmamaları loosly coupled (gevşek bağlı) nesneler olarak anılmalarına sebep olmaktadır. 
-CoR deseni daha çok bolca if-else blokları geçen yerlerde kullanılmalıdır. Yoksa belli bir süre sonra kodlar kontrolden çıkabilir.

Örnek
Bir satın alma sürecinde, ödeme onayının kim tarafından verileceğinde de bu desen göz önüne alınabilir.
Bu senaryoda ödeme talimatını onaylayabilecek olan yetkililer bulunur. 
Ancak gelen ödeme talebinin tutarına göre ilk yetkili personel, talebi bir üst yetkiliye iletmek zorunda olabilir. 
Bu durumda yetkililerin bir sorumluluk zincirinin parçası oldukları düşünülebilir. 
Burada en alt yetkiliye gelen ödeme talebi, gerektiğinde zincirin sonunda yer alan en üst yetkiliye kadar gidebilmelidir. 
Ayrıca bu yetkililerin her biri, birbirlerine sadece bu ödeme talepleri kapsamında bağlı olarak düşünülebilir. 
Bir başka deyişle ödeme onayı için her biri kendi sorumluluklarına sahip iken, farklı işlerde birbirlerinden tamamen bağımsızlardır.

NOT:
Chain Of Responsibility patternde bir request potansiyel alıcılardan birisi bu requesti handle edene kadar zincir boyunca sırayla iletilir. Burada dikkat edilmesi gereken konu client requesti kimin alacağını biliyorsa ve request sadece bir handler tarafından yakalancaksa burada bu patterni kullanmamalıyız. 

16 Kasım 2022 Çarşamba

Abstract Class ve İnterface

Bir sınıf sadece tek bir sınıftan miras alabilir. Fakat birden fazla interfaceyi impelemente edebilir. Abstract ve İnterfacenin en büyük farkı budur.

ABSTRACT CLASS 

Bir base sınıfta var olan metot yada propertynin işleyişi kalıtım alan sınıflarda ihtiyaca göre değiştirilmesi gereken durumlarda kullanılır.
  • Abstract bir sınıf içindeki abstract keywordu ile işaretlenmiş metodların gövdesi boş olur. Bu metodlar abstract sınıftan türeyen subclasslar tarafından override edilerek yazılmalıdır.
  • Absract sınıflardan nesne üretilemez.
  • Absract sınıf içinde abstract olmayan metot yazılabilir.
  • Absract olmayan sınıf içinde abstract metot yazılamaz.
  • Absract sınıfların constructeri vardır.
  • Absract sınıf içinde private eleman olamaz.
  • Abstract sınıf içinde static keywordu kullanılabilir.


























İNTERFACE
Kendisini kalıtım alan sınıfların içinde olması zorunlu olan yapıları gövdeleri boş olarak tanımlar. Tek görevi budur.
  • İnterface içinde olan tüm metotlar kalıtım alan sınıflar tarafından implemente edilip gövdeleri doldurulmak zorundadır
  • Bir sınıf sadece tek bir sınıftan miras alabilir fakat sınırsız sayıda interfaceyi implemente edebilir.
  • Interface içinde metot, property ve indexer gibi yapılar olabilir.
  • İnterfacelerin constructerı yoktur.
  • İnterfacelerden nesne üretilemez.
  • İnterface içerisinde static yapılar olamaz.

15 Kasım 2022 Salı

Nesne Yönelimli Programlama

Nesne Yönelimli Programlama da temel mantık, yapacağımız işlemleri tek bir sınıf içerisinde alt alta yazılmış uzun kodlarla değilde daha kısa yazılmış ve sınıfların mantıksal olarak birbirinden ayrılmış bir şekilde tasarlanmasıdır. Sınıflar içerisinde yapılacak işlemler farklı metotlar içerisinde yazılarak yapının daha sade ve anlaşılır hale gelmesi sağlanır. Burada esas amaç; mantıksal yapıları kullanırken kalıtımdan faydalanmak, sınıfları soyutlamak, ilişkili metotları, değişkenleri kapsüllemek ve bir arayüz vasıtasıyla birden çok sınıfa çok biçimlilik sağlamaktır.


Encapsulation

Oluşturduğumuz sınıftaki değişkenlerin setter ve getter metotları kullanılarak ve bu setter ve getter metotlarına erişim belirleryicilerle belli sınıflardan erişim sağlanmasına izin vermek gibi kontroller encapsulation ile mümkündür.
Encapsulation yazılımcıya oluşturduğu sınıftaki değişkenlerin ve metodların erişimlerini kontrol yetkisi verir. Tanımladığımız bir sınıf içerisindeki değişkenin direkt olarak değiştirilememesi, bunun yerine bizim izin verdiğimiz ölçüde, metotlar aracılığıyla değiştirilmesi gerekmektedir. Bu erişim yetkilerini  Access Modifierlarla belirleriz.



Public: Bu erişim belirleyici ile oluşturulan metot yada propertylere her yerden erişim sağlanır.
Private: Sadece oluşturulduğu sınıf içerisinden erişim sağlanabilir
Protected: Sadece bu clasın ve bu classtan türemiş sınıfların içirisinden erişilebilir. Bu classtan oluşturulan nesneler üzerinden erişemeyiz.
Internal: Sadece içerisinde bulunulan assemly(solution.exe) den erişim sağlanabilir. Bu .dll nin referans eklenip kullanıldığı başka solution içindeki yapılarda kullanılamaz.


İNHERİTANCE

Var olan sınıfın özelliklerini korumak ve bu özelliklere eklenti yapma amacıyla kullanılır. Genelden özele doğru gidilir. Bir sınıf başka bir sınıftan türeyerek o sınıfın public ve protected tanımlı yapılarını devralır.

ABSTRACTİON

Abstraction sayesinde kullanıcıya yapılacak işin fonksiyonelliği sunulur. Bu şekilde kullanıcı kullandığı metodun ne yaptığıyla ilgilenirken, nasıl yaptığıyla ilgilenmez. Bu durumda fonksiyonellik ön plana çıkarken, işin nasıl yapıldığı gizlenir. Yani kullanıcı arabayı çalıştırır, o arabanın ilk tetiklenmeden sonra hangi aşamalardan geçtiği, arka tarafta neler olduğu konularıyla ilgilenmez. Abstraction, interface ve abstract class yapıları ile sağlanır.
interface ve abstract sınıflardan nesne üretilmez.

POLYMORPHİSM

  • Bir nesnenin birden fazla türün davranışını gösterebilmesini sağlamaktır.
  • Base classtan bir referansa , Base classtan türemiş sınıfların nesnesini işaret ettirmektir.


ÖZETLE
Bir sınıf değişken ve metodlardan meydana gelmektedir. Bu sınıf içerisindeki metodların, Bu sınıfı kullanan yapılar tarafından ne yaptığının bilinmesi fakat nasıl yaptığının bilnememesine abstraction, Bu sınıf içerisindeki metod ve değişkenlerin hangi yapılar tarafından erişilebileceğini belirlemeye de Encapsultion denir. Encapsulation Acces Modifierlarla sağlanır.

Nesne ve Sınıf Yapısı

Nesne ve Sınıf yapısı kullanılarak nesneye dayalı programlama yapılmaktadır. Nesneler sınıflardan oluşmaktadır.

Sınıf; Nesnelerin özelliklerini ve işlevlerini tanımlayan şablondur.

Nesne; Çevremizde gördüğümüz özellikleri ve işlevi olan her şeyi nesne olarak tanımlayabiliriz. örn: Telefon, bilgisayar, araba vs. Nesnelerin özellikleri veri tipi ile belirtilebileceği gibi yine bizim tarafımızdan oluşturulan sınıflar aracılığıyla da belirtilebilir. Nesnelerin işlevleri ise Metod Yapısı ile belirtilerek nesnelerin birbirleri arasındaki iletişimi sağlanır.

Bir araba sınıfı içerisinde arabaların genel bir özelliği olarak varsayilanMotorHacmi tanımlanmıştır. Ayrıca işlevsellik olarak da calistir() veya bagajAc() gibi bir çok işlevsellik eklenebilir. Özellikler ve İşlevsellikler tamamen geliştiricilerin ihtiyacına göre düzenlenebilir.

Consructer(Yapıcı Metod)

Bir sınıftan nesne oluşturulduğunda ilk çalışan metotlardır. Biz kod yazarken sınıf içerisinde constructer tanımlamasak da arka tarafta bizim yerimize default olarak bir constructer oluşturulmaktadır. Bu metodlar aracığıyla sınıflara ilk çalıştıklarında vermek istediğimiz değerleri verebilir, varsayılan değerlere farklı değerler atayabilir veya bir metot çalıştırabiliriz. 
Static Constructer bir classtan nesne yaratırken diğer constructerlardan önce ilk bu  çalışır. Parametre almazlar ve bu sınıftan ilk nesne oluşturulduğunda sadece bir kez çalışır bir daha çalışmazlar.















new Araba(); diyerek bir nesne oluşturduğumuzda ilk olarak boş constructera bulacak ve bu constructerın scopuna girmeden parametre alan constructera gidip onun içini çalıştıracak ve daha sonra geriye dönüp boş constructerin scopunu çalıştıracaktır.

Nesne

Sınıflardan oluşturulur. Sınıfların bir instancesidir.
SinifAdi sinifAdi = new SinifAdi();

Referans Nedir ? 
Ram'in Stack bölgesinde tanımlanan ve Heap bölgesindeki nesneleri işaretleyen/referans eden değişkendir. 

















Yukarıdaki sarı nokta referans noktasıdır. Abstract, interface ve classtan  referans noktası oluşturulabilir fakat bu referans noktaları sadece Class türünden nesneyi işaret edebilir. Yani abstract ve interfacelerin new'lenerek nesneleri oluşturulamaz. new keywördü ile bu referans noktalarına bellekten yer tahsis edilir. Eğer ki referans noktası oluşturulur fakat new keywordü ile bellekten yer tahsis edilmezse bu referans noktası null değerini alır.(MyClass m; // null )

Getter ve Setter Metodlar

Yukarıdaki varsayilanMotorHacmi  değişkeninin değerini değiştirmek istiyorsak direkt olarak çağırarak değil de getter setter yapısını kullanarak yapmak en doğru yaklaşımdır.



14 Kasım 2022 Pazartesi

Composite Pattern

- Bütün-parça ilişkisi kurgulamak.
- Bileşik kalıp birbirilerinden farklı olan bir grup nesnenin sanki tek bir bütün nesneymiş gibi davranmalarını sağlarlar. 
- Bileşik kalıpların görevleri nesneleri bir ağaç yapısında birleştirip uygulamanın genelindeki parça bütün ilişkisini yeniden düzenleyip şekillendirmektir.

Problem
Sıklıkla parçaların bir araya gelerek, bir bileşik(composite) oluşturduklarını görürüz.
Bileşik nesne(composite object) parçalardan oluşur.
Böyle durumlarda, tek olan parçalarla, bütün olan bileşik nesne arasındaki ilişkiyi yönetmemiz gereklidir.
Ayrıca istemcilerin tek olan parçalarla, bütün olan bileşik nesneleri aynı şekilde kullanabilmelerini isteriz.
Bu şekilde, bileşik nesneyi kullanmanın istemciye fazladan yük getirmemesini sağlarız

Part ve Whole gibi iki sınıfımız olduğunu varsayarsak, Whole sınıfı Part sınıfının bazı örneklerini içersin. Yukarıdaki diagramın dez avantajını anlamak için folder ve file ile ilgili bir örnek düşünelim. Whole sınıfı folder, file sınıfı ise part olsun. folderlar file içerebilir aynı şekilde folderlar folderda içerebilir.

Çözüm










Decorator Pattern

Decorator tasarım deseninin amacı nesnelere dinamik olarak run-time da yeni özellik eklemektir ve nesnenin  kendisi de eklenen özelliklerden habersiz ve ayrı bir konumda olmalıdır. Yani kodun belli kısımlarında nesnelere belli özellikler kazandırmak istiyorsak ve bunu nesnenin kendi sınıfından ayrıştırılmış bir şekilde yapmak istiyorsak Decorator tasarım desenini kullanmalıyız.

Problem


Yeni bir özellik eklemek istediğimizde Component1 clasından miras alan yeni bir class oluşturacağız. Bu şekilde her yeni özellik eklemek istediğimiz de Component1'i miras alan yeni bir class oluşturmamız gerekiyor. Bu esnek bir yapı değildir. Sınıflara yetkinlik eklemek için miras kullanmanın en temel sorunu, mirasın bir compile-time(derleme zamanı) yapısı olmasıdır.
- Her yeni yetkinlik için kod değişikliği ve tekrar derleme(build) gerekir.
  • Bir nesneye dinamik olarak yeni sorumluluklar nasıl eklenebilir ?
  • Nesneye yeni bir özellik kazandırmak için tek yol miras değildir. Decorator pattern sayesinde miras dışında da nesneye yeni özellik kazandırabiliyoruz.
Çözüm



- Miras ile kurulan  is-a ilişkisi yerine nesne bileşimi ile has-a ilişkisini kullanılır. Component interfacesini implement eden Devorator sınıfı aynı zamanda Componenet sınıfını constructerında parametre olarak almaktadır.
- Yeni sorumlulukları yeni alt sınıflarla yerine getirmektense, alt sınıf ihtiyacını doğuran şeyi bir dekorasyon/bezeme malzemesi olarak görmek ve sınıfın nesnelerine eklemek daha sağlıklıdır.
- Bu şekilde nesnenin en basit halinden başlayarak farklı dekorasyonlar uygulamak mümkün olacaktır.

Ne zaman kullanılır ?
Dekoratör pattern, sınıfları değiştirmeden genişletmek için kullanılmalıdır. Böylece Open Closed Principleye sadık kalmış oluruz. Çoğunlukla logging yada  caching gibi cross-cutting concernler için kullanılır.

Sonuçlar
- Decorator kalıbı, sınıf mirasından daha esnek bir yapı sağlar.
- Çünkü bir nesnenin sahip olabileceği özellikleri-sorumlulukları önceden ön görerek sınıfa eklemek yerine, çalışma zamanında(run-time) isteğe bağlı olarak nesneye eklenmesine izin verir.
- En negatif yanı ise pek çok ufak Decorator nesnesine sahip olmamızdır.
- Esas nesne dekore edildiğinin farkında değildir.  Yani dekoratör ile eklenen özellikler aslında kendi classı içerisinde barındırdığı özellikler değildir.
- Böylece esas nesnenin classı tüm gerekli gereksiz opsiyonları içerisinde barındıran büyük bir class halinden çıkmış olur.
- Tüm decorator classları birbirinden bağımsızdır.

NOT:
Decorator kalıbının Compositeden farkı, Decoratorde sorumluluk decorator nesnelerinde iken Compositede sorumluluk composite nesnededir.
Bu yüzden Decoratorde bütün-parça ilişkisi yoktur. nesnenin süreç içerisinde benzemesi söz konusudur.
Decorator adaptörden de farklıdır çünkü decorator nesnenin arayüzünü değiştirmez, sadece sorumluluk ekler. Adapter ise uyumsuz nesneye tamamen yeni bir arayüz sağlar


Decorator Pattern İmplementasyonu






Bridge Pattern

- Soyutlama ile gerçekleştirmesini birbirinden ayırmak.
- Bridge Pattern soyutlamayı (abstraction) uygulamadan (implementation) ayırarak ikisinin birbirinden bağımsız çalışmasını sağlar. 
- Ana fikir Bileşimi, kalıtıma tercih et

Problem

- Normalde bir absraction ve implementasyonunu ayırmak için kalıtımı kullanırız.
- Absraction clasını farklı şekillerde implemente eden birden çok alt sınıfımız olabilir.(imp1,imp2 vs.)
- Fakat kalıtım ile Base Class ve Sub Class sıkı bir şekilde birbirine bağlanmış olur.
- Base Clası değiştirdiğimizde Sub Class da değişmek zorunda kalabilir.
- Ayrıca kalıtım ile compile-time da bir absraction ile implementasyonu birbirine bağlanmış olur ve implementasyonun run-time da değiştirilmesi imkansız hale gelmiş olur.
- Çünkü kalıtım değiştirilemez. Bir sınıftan run-time da başka bir sınıfı implemente etmesini isteyemeyiz.
- Sonuç olarak kalıtım kullandığımızda 
  • Abstraction ve implementasyon birbirine sıkı bir şekilde bağlanmış olur.
  • Run-time da implementasyonu değiştiremeyiz.

Ana Fikir: 
Soyutlamalar ile onların implementasyonları arasındaki ilişki her zaman is-a olarak yapılmak zorunda değildir.Bu ilişki bazen has-a ile de gösterilebilir ve bu durumda yüksek bağımlılığın getirdiği negatif etkiler aşılabilir.

Çözüm
Bridge kalıbı, soyutlamalar ile onların gerçekleştirmeleri arasında tabi durumda var olan is-a ilişkisini, has-a ilişkisine çevirir.
Bu durumda soyutlamalar ve gerçekleştirmeleri ayrı hiyerarşilerde tutulur.
Aralarında has-a ilişkisi olur.
Bu şekilde iki taraf arasındaki bağımlılığın azalması hedeflenir.




















Run-time da bir implementasyonun seçilebilmesi için compile-time da absraction ve implementasyonun bağlanmasından kaçınılmalıdır.

Bir abstraction ve implementasyon arasındaki kalıcı bindingden kaçınmak istediğimiz de Bridge Patterni kullanabiliriz.


Facade Pattern

- Karmaşık alt sistemi kullanmayı kolaylaştırmak.
- Facade Kalıbı çok geniş boyutlardaki kod parçalarını onlara göre çok daha sadeleştirilmiş arayüzlere indirgenilmesini sağlar. 

Problem
Sistemler tabiatıyla karmaşıktır ama ara yüzlerinin basit olması gerekir.
Çünkü istemcilerin bağımlılıkları en aza indirgenmelidir.
İnterface dediğimiz yapılar sadece sınıflar için değil subsytemler interfacelerin toplandığı bir yapıda olabilir.

Facade, Kurumsal uygulamalardaki katmanlar(tiers/layers) arasındaki ilişkiyi basitleştiren en temel kalıptır.
Dolayısıyla
  • Karmaşık bir sistemin kullanımını basitleştirmek, ona basit bir arayüz sağlamak istersek
  • Karmaşık bir sisteme, az metot çağrısı ile çok iş yapacak şekilde erişmek istersek
  • Katmanlı yapı kullanırken, her katman için bir giriş noktası
  • Yukarıdaki durumlarda Facade Patterni kullanabiliriz













Database erişim
Web kamerası, ses kartı gibi  I/O aygıtına erişim.
Sınıf kütüphaneleri (class library) bu tür kalıplar için verilebilecek en iyi örnekleridir.

Flyweight Pattern

Sistemde çok sayıda oluşturulan küçük nesnelerin ortak kullanılarak sistem kaynaklarının ve hafızanın daha az tüketilmesini sağlar. 
Birçok kez oluşturulan nesnelerin tekrar kullanılarak çok sayıda nesne oluşturulması önlenir.

Problem I
Bazen çözümlermizde ufak-tefek olan çok sayıda nesne kullanmak zorunda kalırız.
  • Örneğin, bir kitabın modellenmesinde kullanılabilecek sayfa, paragraf, satır, kelime ve harf nesneleri bu cinstendir.
  • Bir kitabp 500 sayfadan oluşuyorsa bizim 500 tane sayfa nesnesi mi oluşturmamız gerekir ? yada 8.000 adet paragraf nesnesi ? 
  • Tek bir sayfa nesnesi oluşturup bu sayfa nesnesini reuse edebiliriz. her sayfa geçişinde içini sayfanın içini boşaltıp yeniden doldurmak
Prototype Patternde var olan objeyi referans alarak yeni bir obje yaratıyoruz.
Flyweightte ise var olan objeleri tekrar kullanıyoruz. Yani yeni bir obje yaratmak yerine var olan objenin üzerinde değişiklik yapıyoruz.
örn. Bir oyun yazıyorsak eğer bir asker bir bağlam da Türk askeri olarak gözüküyorken bir başka bağlamda Türk subayı olarak gözükebilir.
Burada aynı nesne üzerinde sadece görüntüyü değiştiriyoruz. Temel nesne aynıdır.
Yada bir asker bir yerde karacı gözükürken başka yerde havacı gözükebilir. Bizim sıfırdan yeni bir havacı nesne yaratmamız yerine
var olan karacı nesnesini alıp içinde bulunduğu bağlamdan dolayı denizci giysisi giydirmemiz çok daha az masraflı olabilir.

örn. Harf nesnemiz olsun. Bu harf nesnemiz satır başındayken herzaman büyük olsun gibi bir kuralımız olabilir.
Aynı nesne satır başındayken büyük, satır ortasındayken küçük olur.
Yani Flyweight nesne, içinde bulunduğu bağlam ile ilgili bir bilgiyi edinebilir ve buna göre davranışını değiştirebilir.(Paragraf başındaysa harfin büyük başlaması)
Bu noktada Flyweight bir nesnenin durumu ile ilgili şu ayrım yapılabilir.
  • İçsel yada asıl durum (intrinsic state) : Konumundan ve contextinden bağımsız bu obje gerçekten ne objesidir. Bu obje a harfi objesi. Bu obje asker objesi.
  • Dışsal ya da ikincil/arizi durum(extrinsic state) : Bu da bağlamsal durumdur. Mesela bir harfin satır başında mı yoksa satır ortasında mı olduğu bağlamsal durumdur. Bu bağlamsal duruma göre ya büyük yada küçük olacaktır.

Proxy Pattern

Bir nesneye erişimi kontrol etmek amacıyla bu nesne yerine geçen ara bir nesne sağlamak.

Problem - I
Farklı sebeplerden dolayı bir nesneye olan erişimi kontrol etmek gerekebilir.
Bu sebepler, güvenlik, maliyet, teknik kısıtlar vs. olabilir.
Güvenlik : Nesnenin kendisinin de nesneye ulaşması tehlikeli olabilir.
Maliyet : Nesneyi oluşturmayı ihtiyaç anına kadar geciktirmek

Problem-II
Teknik kısıtlar : Nesne Erişim dışında olabilir.
  •  Nesne uzak nesnedir, dışarıdan yalıtılmıştır,nesne thread-safe değildir.
Katma değerli hizmetler : Nesneye ulaş ama doğrudan ulaşma. Nesneye erişim öncesinde ve sonrasında farklı işler yapmak gerekebilir.
  • Erişim isteklerini saymak istiyor olabiliriz, Nesneye erişimi düzenlemek ve bir kuyruğa sokmak isteyebiliriz, Ulaşımla ilgili loglar tutmak istiyor olabiliriz.
  •  Nesnenin işi uzun sürmektedir ve bu sebeple senkron yerine asenkrom erişim söz konusudur.Bunu sağlamak için proxy kullanılabilir.
Problem - III
Nesneye erişimin kontrol sebebi durumları, nesne üzerinde gidermeye çalışmak nesnenin kohezyonunu düşürür. örn. Nesnenin erişim sayısını bulmak için nesnenin içine count isminde field koyup nesneye her erişimde bunu arttırabilirz. Fakat Single responlibility prensibine göre bu işi bu sınıfın içinde yapmamız doğru bir çözüm değildir.

Bu kısıtları istemciden yalıtmak gerekir.
  •  İstemci olabildiğince kısıtlardan haberdar olmamalı, sanki asıl nesneyle çalışıyormuş gibi normal çalışmasına devam etmelidir.
  • Şu durumda önemlidir. İstemci önceden asıl nesneye doğrudan ulaşıyordur ama sonrasında katma değerler devreye girmiştir ve istemcide hiç bir değişiklik yapmadan önlem almak gerekir.





Adapter Pattern

 Adaptör kalıp sadece bir sınıfa (class) özel olan arayüzleri diğer sınıflarla uyumlu arayüzler haline getirir. 
Adaptörler uyumlu olmayan arayüzler sebebiyle birbirleri ile çalışamayan sınıflara da birbirleri ile çalışma imkanı sunarlar.
Third party libraryleri projeye ekleme

Problem


Yukarıda clientin iletşime geçtiği Target isimli interfacemiz var. Adapte sınıfımız bu target interfacesinin davranışlarını farklı isimlerde gerçekleştiriyor. 


Hangi problemleri çözer ? 
  • Clientın ihtiyaç duyduğu interfaceye sahip olmayan bir sınıfı nasıl adapte edebiliriz
  • Uyumsuz interfacelere sahip sınıflar nasıl birlikte çalışabilir.

Çözüm


Yukarıda Target interfacesini implemente eden Adapter isminde bir sınıf oluşturuyoruz. Bu Adapter sınıfı Adapte sınıfını referans olarak içerisiyor.

Örnek


11 Kasım 2022 Cuma

Prototype Pattern

Factory ve Absract factory nesnenin NEREDE yaratılacağını, Prototype ve Builder ise nesnenin NASIL yaratılacağını belirler.
Prototip bir nesneyi kullanarak yaratılacak nesneleri belirlemek ve yeni nesneleri prototipi kopyalayarak oluşturmak.

Problem-I
- Uygulamalarda sıklıkla iş alanı(businesss domain) sınıflarında nesneler oluştururuz.
- Bu nesneler zaman zaman yüksek karmaşıklıkta olurlar. Yani constructera cok fazla parametre geçmek gerekiyorsa karmaşıklaşır.
- Nesnelerin karmaşık olması, durumlarının(state) karmaşık olması demektir.

Constracteri karmaşık olan nesleri yaratmak maliyetlidir. Bu maliyetten kurtulmak için static olan tek bir nesneyi önceden hazırlayıp  daha sonra bu nesneyi kopyalayarak buna benzer bir nesneler oluşturabiliriz
Shallow Copy : Nesnenin birebir aynısı referansıda aynı.
Deep Copy : Tamamen farklı bir nesne oluşturmak. Referansıda farklı

Builder Pattern

Aşağıdaki gibi farklı parametrelere sahip bir çok constructera sahip bir Employe sınıfı oluşturacağımızı varsayarsak; Her bir özellik için yeni bir constructer oluşturmamız gerekecektir.


Çözüm

Sıklıkla nesneler dolayısıylada yaratılmaları karmaşıktır.
Böyle karmaşık nesneleri constructerla yaratmak yerine süreç içerisinde yaratılmasını, yani teker teker eklenerek inşa edilmesini önerir.
Bir nesnenin karmaşık olduğunun en temel göstergesi, çok parametre alan constructerlarının olmasıdır.

En basit haliyle Builder, nesnenin varsayılan constructırını çağırıp sonrasında SET metotlarıyla nesneyi bina eder ve oluşan nesneyi istemciye geri döndürür.

Builder kalıbının amacı, karmaşık olan nesne yaratma sürecini yönetmektir.
Factory Method ve Abstract Factory kalıpları ise sadece nesne yaratma sorumluluğunu devir almak içindir. Nesne tabanlı programlamanın özü sınıflara dayanır. 
Sınıflardan nesneler yaratırız. Bunu yapmak için de constructorları kullanırız. 
Sınıfımızda bulunan field sayısı fazla olursa bundan dolayı birden çok constructora ihtiyaç duyabiliriz. 
Haliyle her bir field eklendiğinde yeni bir constructor ekleme ihtiyacı hissedebiliriz. 
Çünkü nesneyi oluştururken hangi field başta atama yapılacak ya da yapılmayacak bilemeyebiliriz. 
İşte bu uzayıp giden parametre sayısından, karmaşık constructorlardan kurtarmak için Builder Pattern güzel bir çözüm sunuyor

Ne zaman kullanılmalı ?
- Dinamik olarak farklı parametrelerle birden çok constructer tanımlamamız gerektiğinde 
- Karmaşık bir nesne oluşturduğumuzda büyük adımları daha küçük adımlara ayırmamız gerektiğinde

Abstract Factory Pattern

Amaç: Birbirleriyle ilgili yada bağımlı nesne ailelerini, nesnelerin somut sınıflarını belirtmeden yaratmak için bir  arayüz sağlanır.
Absract Factory tek bir nesne yerine, nesne ailesi oluşturmak için kullanılan bir kalıptır.
Factory Method tek bir nesnenin, Absract Factoy ise birden fazla nesnenin yaratılmasını soyutlar.
Bu amaçla Absract Factory birden fazla factory metoda sahiptir.
Factory metodla  bir nesne oluştururuz. Absract Fctory ile ise birden fazla ilişkili nesne varsa ve bunları birlikte oluşturmamız gerekirse her bir factory metodun bir araya getirildiği bir sınıfta oluşturmamızı sağlar.

Elimizdeki nesneler, bir nesne ailesi oluşturuyorlarsa yani bu nesneler bir birleriyle ilgili nesnelerse her birisi için ayrı ayrı oluşturulan ve farklı sınıflara konan Factory Metodların bir sınıfta toplanması makuldur.
Böylece bir sınıfta toplanan factory metodlar kohezyonu düşürmez.
Abscract factory, birden fazla factory method bir araya getirilerek oluşturulur.





Factory Method Pattern

 Factory Method( Üretici Method) Nesneyi Nerede Yaratmalıyız ?

Nesnelerin yaratılmaları soyutlamakta ve üretici method dediğimiz Factory metoduna havale edilmektedir..
Nesne yaratma sorumluğu Clientin üzerinden alınmış olur.
Factory method sayesine, bir çok istemci tarafından yeniden kullanılabilecek bir nesne oluşturma mantığı oluşturulur. Böyle new ile nesne yaratma sürecinin uygulama içerisine yayılması önlenmiş olur.

Eğer Employe,Manager hepsi için Constructer parametre sayısı aynı ise aynı factory intefacesini hepsi implemente edebilir.



Eğer Employe,manager hepsi için contructer parametre sayısı farklı ise hepsi için ayrı ayrı EmployeFactory, ManagerFactory oluşturulması gerekir.



Factory Method tek bir nesne yaratmaktan sorumludur.Yaratılacak nesne bir değil birden çok ise 
yapılacak şey birden fazla Factory Method kullanmaktır.

Elimizde Button,List ve Table gibi componentlerimiz var.Bunların arasında bir ilişki henüz sezmedik.
Bunları yaratan GuiFactory isimli bir interface var. ve bunun üzerindeki create metodunu override eden
ButtonFactory,ListFactory,ButtonFactory gibi yapılarımız var ve bunlarla objeyi oluşturuyoruz..


inner Factory