Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
C#’da nesne yönelimli tasarım desenleri, yazılım geliştirme sürecinde yaygın olarak kullanılan çözüm örüntüleridir. Bu desenler, tekrar eden problemleri çözmek için kullanılan genel yaklaşımları ifade eder ve yazılımın esnekliğini, okunabilirliğini ve yeniden kullanılabilirliğini artırır.
Singleton Pattern (Tekillik Deseni): Tekillik deseni, bir sınıfın yalnızca bir örneğinin oluşturulmasını ve bu örneğe global bir erişim sağlanmasını sağlar. Bu desen genellikle kaynak tüketimini azaltmak veya paylaşılan bir kaynağa tek bir erişim noktası sağlamak için kullanılır. Örneğin:
public class Singleton
{
private static Singleton instance;
private Singleton() { }
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
Factory Method Pattern (Fabrika Metodu Deseni): Fabrika metodu deseni, bir süper sınıfın alt sınıflarının nasıl oluşturulacağını belirleyen bir yöntem sağlar. Bu desen, bir nesne oluşturmak için genel bir arayüz sağlar, ancak alt sınıfların hangi sınıfların oluşturulacağını belirlemesine izin verir. Örneğin:
public abstract class Creator
{
public abstract Product FactoryMethod();
}
public class ConcreteCreator : Creator
{
public override Product FactoryMethod()
{
return new ConcreteProduct();
}
}
Observer Pattern (Gözlemci Deseni): Gözlemci deseni, bir nesne durumunda değişiklik olduğunda bağımlı nesnelerin otomatik olarak güncellenmesini sağlar. Bu desen, birçok yayın/abone senaryosunda kullanılır. Örneğin:
public interface IObserver
{
void Update(ISubject subject);
}
public interface ISubject
{
void Attach(IObserver observer);
void Detach(IObserver observer);
void Notify();
}
public class ConcreteSubject : ISubject
{
private List<IObserver> observers = new List<IObserver>();
public void Attach(IObserver observer)
{
observers.Add(observer);
}
public void Detach(IObserver observer)
{
observers.Remove(observer);
}
public void Notify()
{
foreach (var observer in observers)
{
observer.Update(this);
}
}
}
Decorator Pattern (Dekoratör Deseni): Dekoratör deseni, bir nesneyi dinamik olarak genişletmek için kullanılır. Bu desen, sınıfın alt sınıflarını çok katmanlı bir şekilde genişletmeyi sağlar ve nesneye dinamik olarak davranış eklemeyi mümkün kılar. Örneğin:
public abstract class Pizza
{
public abstract string GetDescription();
public abstract double GetCost();
}
public class Margherita : Pizza
{
public override string GetDescription()
{
return "Margherita Pizza";
}
public override double GetCost()
{
return 6.99;
}
}
public abstract class PizzaDecorator : Pizza
{
protected Pizza _pizza;
public PizzaDecorator(Pizza pizza)
{
_pizza = pizza;
}
public override string GetDescription()
{
return _pizza.GetDescription();
}
public override double GetCost()
{
return _pizza.GetCost();
}
}
public class Cheese : PizzaDecorator
{
public Cheese(Pizza pizza) : base(pizza)
{
}
public override string GetDescription()
{
return _pizza.GetDescription() + ", Cheese";
}
public override double GetCost()
{
return _pizza.GetCost() + 1.5;
}
}
Bu örnekler, C#’da sıkça kullanılan bazı temel nesne yönelimli tasarım desenlerini kapsamaktadır. Tasarım desenleri, yazılım geliştirme sürecinde çeşitli problemleri çözmek için güçlü araçlardır ve doğru şekilde kullanıldığında, kodunuzun daha okunabilir, esnek ve yeniden kullanılabilir olmasını sağlar.
“Tasarım Desenleri”, yazılım geliştirme sürecinde sıkça karşılaşılan problemleri çözmek için geliştirilmiş genel çözüm yaklaşımlarıdır. Bu desenler, deneyimli yazılım geliştiricileri tarafından yıllar boyunca geliştirilmiş ve belirli sorunları çözmek için etkili olduğu kanıtlanmıştır.
Tasarım desenleri hakkında derinlemesine bilgi sahibi olmak, bir yazılım geliştiricisi için son derece önemlidir.
Tasarım desenlerini derinlemesine anlamak, yazılım geliştirme sürecinizde daha iyi kararlar vermenize, kodunuzu daha iyi organize etmenize ve daha iyi bir yazılım mimarisi oluşturmanıza yardımcı olur. Bu nedenle, C# programlama dilinde tasarım desenlerine odaklanarak, yazılım geliştirme becerilerinizi geliştirebilir ve daha etkili yazılım üretebilirsiniz.
Nesne yönelimli programlama (OOP), yazılım geliştirme sürecinde kullanılan bir programlama paradigmasıdır. C# gibi dillerde yaygın olarak kullanılan bir yaklaşımdır. OOP’nin temel amacı, yazılımı nesnelerin bir araya gelmesi ve etkileşimi üzerine kurmaktır.
C#, Java, C++, Python gibi diller, nesne yönelimli programlamanın temel kavramlarını destekler ve bu kavramları kullanarak karmaşık yazılım sistemleri geliştirmeyi sağlar. Bu nedenle, nesne yönelimli programlamayı anlamak ve kullanmak, modern yazılım geliştirme süreçlerinde temel bir beceridir. Bu kavramları anlayarak, yazılım projelerinizde daha modüler, esnek ve sürdürülebilir kodlar yazabilirsiniz.
“Nesne Yönelimli Programlama” (OOP), yazılım geliştirme sürecinde kullanılan bir programlama paradigmasıdır ve “Tasarım Desenleri” ile OOP arasında bazı ayrımlar bulunmaktadır.
Sonuç olarak, OOP ve tasarım desenleri arasında bazı ayrımlar bulunmaktadır. OOP, geniş bir programlama paradigmasıdır ve tasarım desenleri sadece bu paradigmanın bir parçasıdır. Tasarım desenleri, belirli problemleri çözmek için geliştirilmiş genel çözüm örüntüleridir ve OOP’nin sadece bir yönünü temsil ederler.
C#, Nesne Yönelimli Programlama ve Tasarım Desenleri, yazılım geliştirme sürecinde birlikte kullanılarak daha esnek, sürdürülebilir ve yeniden kullanılabilir yazılım sistemlerinin geliştirilmesine olanak sağlar. Bu nedenle, bu konuların derinlemesine anlaşılması ve etkin bir şekilde uygulanması, başarılı bir yazılım geliştirme pratiği için önemlidir.
Tasarım desenleri (design patterns), yazılım geliştirme sürecinde tekrar eden problemleri çözmek için geliştirilmiş genel çözüm örüntüleridir. Bu desenler, deneyimli yazılım geliştiricileri tarafından yıllar boyunca geliştirilmiş ve belirli sorunları çözmek için etkili olduğu kanıtlanmıştır.
Tasarım desenleri, yazılım geliştirme sürecinde kodun daha esnek, sürdürülebilir ve yeniden kullanılabilir olmasını sağlar. Bu nedenle, tasarım desenlerinin derinlemesine anlaşılması ve etkin bir şekilde uygulanması, yazılım geliştirme pratiğinin önemli bir parçasıdır.
Tasarım desenlerinin neden gerektiği konusu, yazılım geliştirme sürecinde karşılaşılan tekrar eden problemleri çözmek ve yazılımın daha esnek, sürdürülebilir ve yeniden kullanılabilir olmasını sağlamakla ilgilidir.
Tasarım desenleri, yazılım geliştirme sürecinde tekrar eden problemleri çözmek, kodun daha esnek ve sürdürülebilir olmasını sağlamak, yazılımın daha okunabilir ve bakımı daha kolay olmasını sağlamak ve yazılımın yeniden kullanılabilirliğini artırmak için önemlidir. Bu nedenle, tasarım desenlerinin etkili bir şekilde kullanılması, başarılı bir yazılım geliştirme pratiğinin temel bir parçasıdır.
Tasarım desenleri, yazılım geliştirme sürecinde tekrar eden problemleri çözmek ve yazılımın daha esnek, sürdürülebilir ve yeniden kullanılabilir olmasını sağlamak için önemli bir rol oynamaktadır. Christopher Alexander’ın mimarlık alanındaki çalışmalarından başlayarak, GoF kitabının yayınlanmasına ve günümüzdeki geniş kabulüne kadar uzanan bir tarihsel evrimi temsil ederler.
Tasarım desenleri genellikle üç ana kategori altında incelenir: Creational (Yaratımsal), Structural (Yapısal) ve Behavioral (Davranışsal). Her kategori, farklı türde problemleri çözmek için tasarlanmış desenleri içerir.
Her kategori, belirli bir türde problemleri çözmek için tasarlanmış desenleri içerir. Örneğin, Creational desenler, nesnelerin oluşturulması ve birleştirilmesiyle ilgili sorunları çözmek için kullanılırken, Structural desenler, sınıf ve nesne yapısını düzenlemek için kullanılır. Behavioral desenler ise nesneler arasındaki iletişim ve davranışları yönetmek için kullanılır.
Tasarım desenlerinin bu kategorilere ayrılması, geliştiricilere belirli türdeki problemlere yönelik çözüm önerilerini daha kolay tanımlama ve uygulama imkanı sunar. Bu desenlerin bilinmesi, yazılım geliştirme sürecinde daha etkili ve modüler kod yazma yeteneğini artırır ve genellikle yazılımın daha esnek, sürdürülebilir ve yeniden kullanılabilir olmasını sağlar.
Yazılım tasarım desenlerini kullanmak, yazılım geliştirme sürecinde tekrar eden problemleri çözmek ve daha esnek, sürdürülebilir ve yeniden kullanılabilir kodlar oluşturmak için önemlidir.
Yazılım tasarım desenlerini kullanmak, yazılım geliştirme sürecinde tekrar eden problemleri çözmek ve daha esnek, sürdürülebilir ve yeniden kullanılabilir kodlar oluşturmak için güçlü bir araçtır. Bu nedenle, tasarım desenlerinin kullanılması yazılım geliştirme sürecinin önemli bir parçasıdır ve geliştiricilerin bu konuda derin bir anlayışa sahip olmaları önemlidir.
ılım tasarım desenlerinin kullanımı birçok avantaj sağlasa da, bazı dezavantajları da bulunmaktadır. Bu dezavantajlar, tasarım desenlerinin yanlış kullanımından, aşırı kullanımından veya belirli durumlarda uygun olmamasından kaynaklanabilir.
Yazılım tasarım desenlerinin bu dezavantajlarına rağmen, doğru şekilde kullanıldığında ve uygun bağlamlarda uygulandığında, kodun daha esnek, sürdürülebilir ve yeniden kullanılabilir olmasını sağlayabilirler. Bu nedenle, geliştiricilerin tasarım desenlerini dikkatli bir şekilde kullanması ve her durumda uygun deseni seçmesi önemlidir.
Creational patterns (Yaratımsal desenler), nesnelerin nasıl oluşturulacağı ve birleştirileceğiyle ilgili problemleri çözmek için tasarlanmıştır. Bu desenler, nesne oluşturma sürecini soyutlar ve kodun daha esnek ve yeniden kullanılabilir olmasını sağlar.
Bu creational patternler, C# dilinde nesnelerin oluşturulması ve yapılandırılmasıyla ilgili çeşitli problemleri çözmek için kullanılabilir. Her biri farklı senaryolar için tasarlanmıştır ve uygun şekilde kullanıldığında, kodun daha esnek, sürdürülebilir ve yeniden kullanılabilir olmasını sağlar.
Structural patterns (Yapısal desenler), yazılım bileşenlerinin nasıl bir araya getirileceği ve yapılandırılacağıyla ilgili problemleri çözmek için tasarlanmıştır. Bu desenler, sınıf ve nesneler arasındaki ilişkileri düzenler ve bileşenler arasındaki etkileşimi kolaylaştırır. C# dilinde birçok yapısal desen bulunmaktadır.
Bu yapısal desenler, C# dilinde sınıf ve nesnelerin bir araya getirilmesi ve yapılandırılmasıyla ilgili çeşitli problemleri çözmek için kullanılabilir. Her biri farklı senaryolar için tasarlanmıştır ve uygun şekilde kullanıldığında, kodun daha esnek, sürdürülebilir ve yeniden kullanılabilir olmasını sağlar.
Behavioral patterns (Davranışsal desenler), nesneler arasındaki davranışları ve iletişimi düzenlemek için tasarlanmıştır. Bu desenler, nesnelerin birbirleriyle nasıl etkileşimde bulunacaklarını ve davranacaklarını belirler.
Bu davranışsal desenler, C# dilinde nesneler arasındaki iletişimi düzenlemek ve değişen durumlara uyum sağlamak için kullanılabilir. Her biri farklı senaryolar için tasarlanmıştır ve uygun şekilde kullanıldığında, kodun daha esnek, sürdürülebilir ve yeniden kullanılabilir olmasını sağlar.
Iterator deseni, bir koleksiyonun elemanlarına sırayla erişmek için bir arabirim sağlar ve koleksiyonun yapısını gizler. Bu desen, bir döngü kullanarak koleksiyonun her bir elemanına erişmeyi ve bu elemanlar üzerinde işlem yapmayı sağlar. Iterator deseni, koleksiyonun yapısını değiştirmeden veya koleksiyonun iç yapısını müşterilere açıklamadan koleksiyon üzerinde döngü yapmayı kolaylaştırır.
Iterator deseni genellikle “Iterator” ve “Aggregate” olmak üzere iki ana bileşenden oluşur:
Iterator deseni, bir dizi eleman içeren koleksiyonlarda kullanışlıdır ve koleksiyonun elemanlarına erişimi standartlaştırır. Bu desen, koleksiyonun yapısını gizleyerek koleksiyon üzerinde değişiklikler yapılmasını ve koleksiyonun iç yapısının müşterilere açıklanmasını önler. Bu da kodun daha modüler ve sürdürülebilir olmasını sağlar.
C# dilinde, Iterator deseni genellikle “IEnumerable” ve “IEnumerator” arabirimleri kullanılarak uygulanır. IEnumerable arabirimi, koleksiyon üzerinde döngü yapılabilmesi için GetEnumerator() metodunu sağlar ve IEnumerator arabirimi, koleksiyonun elemanlarına erişim için MoveNext(), Reset() ve Current metodlarını sağlar. Bu arabirimler, .NET Framework’te bulunan koleksiyonların çoğunda kullanılır ve Iterator desenini uygulamak için kullanılabilirler.
C#’da üretilen veriler için açık yineleyici (explicit iterator) uygulaması, bir sınıfın öğelerine birbirini takip eden bir şekilde erişmek için bir mekanizma sağlar. Bu, özellikle büyük miktarlarda veri üreten veya dinamik olarak oluşturulan veri yapılarıyla çalışırken kullanışlıdır. Bu tür veri yapılarına örnek olarak, sonsuz bir dizi, belirli bir kurala göre üretilen veri koleksiyonları veya büyük veri tabanlarından alınan kayıtlar verilebilir.
using System;
using System.Collections;
using System.Collections.Generic;
// Örnek bir sınıf: Sonsuz bir sayı dizisi üreten bir sınıf
public class InfiniteNumbers : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
int number = 0;
while (true)
{
yield return number++; // Sonsuz dizi elemanlarını üret
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator(); // Genel GetEnumerator metoduna yönlendirme
}
}
class Program
{
static void Main(string[] args)
{
InfiniteNumbers numbers = new InfiniteNumbers();
// Açık yineleyici kullanımı
foreach (var number in numbers)
{
Console.WriteLine(number);
if (number >= 10) // Sadece ilk 10 sayıyı göster
break;
}
}
}
Yukarıdaki örnekte, InfiniteNumbers
adlı bir sınıf, sonsuz bir dizi oluşturan bir sınıfı temsil etmektedir. Bu sınıf, IEnumerable<int>
arabirimini uygular, bu da bu sınıfın yineleyici kullanımını mümkün kılar. GetEnumerator()
metodu, sonsuz bir dizi elemanını üretirken yield return
ifadesini kullanarak bir sonraki elemanı döndürür.
InfiniteNumbers
sınıfının bir örneği oluşturulduktan sonra, bu örneğin bir döngü içinde kullanılmasıdır. foreach
döngüsü, numbers
örneğinin her bir elemanına erişmek için açık yineleyiciyi kullanır. foreach
döngüsü, belirtilen koşul gerçekleşene kadar çalışır ve her döngü adımında bir sonraki elemana geçer.
Bu örnekte, InfiniteNumbers
sınıfı özel bir durum oluşturur ve açık yineleyici ile bu durumda başa çıkmak kolaydır. Ancak, farklı senaryolarda, belirli bir veri yapısının veya veri kaynağının el ile dolaşılması gerekebilir. Bu durumda, sınıf içinde bir yineleyici (iterator) yöntemi oluşturmak ve bu yöntemi çağırmak gerekebilir.
Bu tür özel veri yapılarını dolaşırken açık yineleyici kullanımı, performansı artırabilir, bellek kullanımını azaltabilir ve kodun daha temiz ve okunabilir olmasını sağlayabilir. Bu nedenle, büyük veri kümesi veya dinamik olarak oluşturulan veri yapıları ile çalışırken açık yineleyici uygulaması önemli bir teknik olabilir.
C#’da LINQ (Language Integrated Query), veri koleksiyonları üzerinde sorgular oluşturmak ve işlem yapmak için güçlü bir araçtır. LINQ kullanarak, C# dilinde yineleyicileri (iterators) birleştirmek ve karmaşık sorgular oluşturmak oldukça kolaydır. Bu, veri koleksiyonları üzerinde filtreleme, sıralama, gruplama ve dönüşümler gibi çeşitli işlemleri gerçekleştirmenizi sağlar.
var filteredList = myList.Where(item => item.Property > 10).OrderBy(item => item.Property);
4.Gruplama ve Dönüşümler:
var groupedData = myList.GroupBy(item => item.Category);
var transformedData = myList.Select(item => new { Name = item.Name, Value = item.Property * 2 });
5.Birleştirme ve Birleştirilmiş Sonuçlar:
var joinedData = myList1.Join(myList2, item1 => item1.Key, item2 => item2.Key, (item1, item2) => new { Item1 = item1, Item2 = item2 });
var concatenatedList = myList1.Concat(myList2);
LINQ, C# dilinde yineleyicileri birleştirmek ve veri koleksiyonları üzerinde çeşitli işlemler gerçekleştirmek için güçlü bir araçtır. Bu sayede, karmaşık veri manipülasyonları ve sorguları kolaylıkla gerçekleştirebilirsiniz. LINQ’in bu esnekliği, kodunuzu daha okunabilir, temiz ve sürdürülebilir hale getirebilir.
Factory Method tasarım deseni, bir süper sınıfın alt sınıflarının nesne oluşturma sürecini, alt sınıflara bırakması için bir çerçeve sağlar. Bu desen, nesne oluşturma sürecini genelleştirir ve alt sınıfların bu süreci özelleştirmesine olanak tanır. Bu sayede, bir süper sınıf, nesne oluşturma sürecinin detaylarından soyutlanır ve alt sınıflar, kendi ihtiyaçlarına göre nesneleri nasıl oluşturacaklarını belirleyebilirler.
Factory Method deseni genellikle şu bileşenlerden oluşur:
Factory Method deseninde, Creator sınıfı, nesne oluşturma sürecinin genel yapısal taslağını belirlerken, Concrete Creator sınıfları, bu sürecin detaylarını uygular. Bu, yaratıcı sınıfın alt sınıflarının, hangi türde nesnelerin oluşturulacağını belirlemesine olanak tanır ve nesne oluşturma sürecini alt sınıflara bırakır.
Factory Method deseni, aşağıdaki durumlar için uygundur:
Factory Method deseni, birçok tasarım deseniyle birlikte kullanılabilir ve uygulama kodunun daha esnek, sürdürülebilir ve genişletilebilir olmasını sağlar.
Factory Method deseni, bir süper sınıfın alt sınıflarının nesne oluşturma sürecini, alt sınıflara bırakması için bir çerçeve sağlar. Bu desen genellikle farklı alt sınıfların belirli bir işlevselliği farklı şekillerde uygulaması gerektiğinde kullanılır. Bir işlevselliğin hangi alt sınıf tarafından gerçekleştirileceğinin dinamik olarak belirlenmesi gerektiğinde Factory Method deseni ideal bir çözümdür.
Bu senaryoyu daha iyi anlamak için bir örnek düşünelim:
Örneğin, bir uygulama içinde farklı veritabanlarına bağlanma işlevselliği olsun. Uygulamanız MySQL, PostgreSQL ve SQLite gibi farklı veritabanlarına bağlanabilmelidir. Her bir veritabanı türü için farklı bağlantı nesneleri ve bağlantı işlevselliği gerekebilir. Ancak, uygulama seviyesinde hangi veritabanına bağlanılacağı çalışma zamanında belirlenebilir.
Bu senaryoda Factory Method deseni şu şekilde uygulanabilir:
Creator (Yaratıcı):
public abstract class DatabaseConnector
{
public abstract Connection Connect();
}
Concrete Creators (Somut Yaratıcılar):
public class MySqlConnectionCreator : DatabaseConnector
{
public override Connection Connect()
{
return new MySqlConnection();
}
}
public class PostgreSqlConnectionCreator : DatabaseConnector
{
public override Connection Connect()
{
return new PostgreSqlConnection();
}
}
Product (Ürün):
public abstract class Connection
{
public abstract void Open();
public abstract void Close();
}
Concrete Products (Somut Ürünler):
public class MySqlConnection : Connection
{
public override void Open()
{
// MySQL veritabanına bağlanma işlemleri
}
public override void Close()
{
// MySQL veritabanı bağlantısını kapatma işlemleri
}
}
public class PostgreSqlConnection : Connection
{
public override void Open()
{
// PostgreSQL veritabanına bağlanma işlemleri
}
public override void Close()
{
// PostgreSQL veritabanı bağlantısını kapatma işlemleri
}
}
Bu yapı, uygulama seviyesinde dinamik olarak belirlenen bir veritabanı türüne göre doğru bağlantı nesnesini oluşturmak için kullanılabilir. Örneğin:
DatabaseConnector connector;
if (userChoosesMySQL)
{
connector = new MySqlConnectionCreator();
}
else
{
connector = new PostgreSqlConnectionCreator();
}
Connection connection = connector.Connect();
connection.Open();
// Veritabanına bağlanma işlemleri
connection.Close();
Bu şekilde, uygulama seviyesinde hangi veritabanı türünün kullanılacağı belirlenir ve buna göre doğru bağlantı nesnesi oluşturulur. Bu dinamik yapı, Factory Method deseninin gücünü gösterir ve kodun daha esnek, sürdürülebilir ve genişletilebilir olmasını sağlar.
Factory Method tasarım deseni, bir süper sınıfın alt sınıflarının nesne oluşturma sürecini, alt sınıflara bırakması için bir çerçeve sağlar. Bu desen, nesne oluşturma sürecini genelleştirir ve alt sınıfların bu süreci özelleştirmesine olanak tanır. Bu sayede, bir süper sınıf, nesne oluşturma sürecinin detaylarından soyutlanır ve alt sınıflar, kendi ihtiyaçlarına göre nesneleri nasıl oluşturacaklarını belirleyebilirler.
Unit testing (birim test) ise yazılan kodun parçalarının, yazılım geliştirme sürecinde ayrı ayrı ve bağımsız olarak test edilmesi sürecidir. Factory Method deseni, birim testlerde de oldukça faydalıdır ve kodun test edilebilirliğini artırır.
Factory Method deseninin birim testlerle kullanımını daha iyi anlamak için basit bir örnek üzerinden ilerleyelim. Bu örnekte, bir matematik işlemi yapan bir sınıf oluşturacağız ve bu sınıfı test etmek için Factory Method desenini kullanacağız.
Öncelikle, matematik işlemi yapan bir arayüz oluşturalım:
public interface IOperation
{
int Calculate(int a, int b);
}
Ardından, bu arayüzü uygulayan somut sınıflar oluşturalım:
public class AdditionOperation : IOperation
{
public int Calculate(int a, int b)
{
return a + b;
}
}
public class SubtractionOperation : IOperation
{
public int Calculate(int a, int b)
{
return a - b;
}
}
Şimdi, Factory Method desenini kullanarak işlem sınıflarını oluşturan bir Creator sınıfı oluşturalım:
public abstract class OperationFactory
{
public abstract IOperation CreateOperation();
}
Bu Creator sınıfından türetilmiş somut yaratıcı sınıfları oluşturalım:
public class AdditionOperationFactory : OperationFactory
{
public override IOperation CreateOperation()
{
return new AdditionOperation();
}
}
public class SubtractionOperationFactory : OperationFactory
{
public override IOperation CreateOperation()
{
return new SubtractionOperation();
}
}
Şimdi, bu yapıyı birim testlerde kullanarak test edelim. İlk olarak, bir Factory Method ile birim testlerde mock nesneler oluşturan bir test sınıfı oluşturalım:
public class TestOperationFactory
{
[Fact]
public void TestAdditionOperation()
{
// Arrange
OperationFactory factory = new AdditionOperationFactory();
IOperation operation = factory.CreateOperation();
// Act
int result = operation.Calculate(3, 2);
// Assert
Assert.Equal(5, result);
}
[Fact]
public void TestSubtractionOperation()
{
// Arrange
OperationFactory factory = new SubtractionOperationFactory();
IOperation operation = factory.CreateOperation();
// Act
int result = operation.Calculate(3, 2);
// Assert
Assert.Equal(1, result);
}
}
Bu test sınıfı, Factory Method desenini kullanarak farklı işlem türlerini test etmek için mock nesneler oluşturur. Her bir test metodu, ilgili işlem türü için bir Factory sınıfı oluşturur ve bu fabrika yöntemini kullanarak işlem nesnesini alır. Sonra, bu işlem nesnesini kullanarak birim testlerini gerçekleştirir.
Bu örnek, Factory Method deseninin birim testlerde nasıl kullanılacağını göstermektedir. Bu desen, birim testlerin daha modüler ve esnek olmasını sağlar, çünkü işlem nesnelerinin oluşturulması alt sınıflara bırakılarak kod tekrarını önler ve birim testlerin kolayca değiştirilmesini sağlar.
Adapter Pattern, diğer bir deyişle Wrapper Pattern olarak da bilinir, farklı arayüzleri birbirine uyumlu hale getirmek için kullanılan bir yapısal tasarım desenidir. Bu desen, bir sınıfın arayüzünü, bir başka arayüze dönüştürmek için kullanılır. Böylece, bir sınıfın kullanımını, beklenen bir arayüzü kullanmak için uygundur.
Adapter Pattern’ın temel amacı, iki uyumsuz arayüz arasında köprü oluşturmaktır. Bu, yeni bir sınıf oluşturmadan var olan sınıfları uyumlu hale getirmeyi sağlar. Adapter Pattern’ın genellikle üç temel bileşeni vardır:
Adapter Pattern’ın temel prensibi, adaptör sınıfının, istemcinin beklediği arayüzü uygulaması ve bu arayüzü kullanarak adaptörün Adaptee’ye yönlendirmesi veya dönüştürmesidir. Bu, kodun yeniden kullanılabilirliğini artırır ve mevcut kodu değiştirmeden yeni bir arayüzle uyumlu hale getirilmesini sağlar.
Adapter Pattern, aşağıdaki durumlar için uygun olabilir:
Adapter Pattern, kodun daha modüler, esnek ve sürdürülebilir olmasını sağlar. Bu desen, farklı arayüzler arasında geçiş yapmanın gerektiği durumlarda çok kullanışlıdır ve yazılım projelerinde sıkça karşılaşılan bir sorunu çözmek için etkilidir.
Adapter Pattern’ı C# ile FileStream sınıfını ILogger arayüzüyle uyumlu hale getirmek için kullanabiliriz. Bu senaryoda, FileStream sınıfının işlevselliğini ILogger arayüzüne dönüştüren bir adaptör sınıfı oluşturacağız.
Öncelikle, ILogger arayüzümüzü tanımlayalım:
public interface ILogger
{
void Log(string message);
}
Ardından, adaptör sınıfımızı oluşturalım. Bu sınıf, FileStream’ın işlevselliğini ILogger arayüzüyle uyumlu hale getirecektir:
public class FileStreamAdapter : ILogger
{
private readonly string _filePath;
public FileStreamAdapter(string filePath)
{
_filePath = filePath;
}
public void Log(string message)
{
// FileStream'ı kullanarak dosyaya loglama işlemi yapılır
using (var streamWriter = new StreamWriter(_filePath, true))
{
streamWriter.WriteLine(message);
}
}
}
Bu adaptör sınıfı, ILogger arayüzünü uygular ve içerisinde bir FileStream nesnesi oluşturur. Log metodu, aldığı mesajı FileStream ile dosyaya yazma işlemini gerçekleştirir.
Son olarak, bu adaptör sınıfını kullanarak FileStream’ı ILogger arayüzüyle kullanabiliriz:
class Program
{
static void Main(string[] args)
{
// Adaptörü kullanarak FileStream'ı ILogger arayüzüyle kullanma
ILogger logger = new FileStreamAdapter("log.txt");
logger.Log("Log this message");
// Diğer ILogger implementasyonları da burada kullanılabilir
}
}
Bu kod örneği, FileStream sınıfını ILogger arayüzüyle uyumlu hale getiren bir adaptör kullanarak bir dosyaya loglama işlemi gerçekleştirir. Bu sayede, FileStream sınıfı ILogger arayüzünü uygulamış gibi davranır ve mevcut ILogger uygulamaları ile birlikte kullanılabilir.
Bu örnek, Adapter Pattern’ın gücünü gösterir ve farklı arayüzler arasında geçiş yapmanın gerektiği durumlarda nasıl kullanılabileceğini açıklar. Adapter Pattern, mevcut kodun değiştirilmesini önlerken, farklı arayüzler arasında uyumlu bir köprü oluşturmayı sağlar.
Adapter Pattern, farklı arayüzler arasında uyumsuzluk olduğunda bu arayüzleri birbirine bağlamak için kullanılan bir yapısal tasarım desenidir. ViewModel mapping için Adapter Pattern kullanılması durumunda, genellikle farklı veri modelleri veya sınıflar arasındaki uyumsuzluğu çözmek için kullanılır.
Bir uygulama geliştiricisi, MVC (Model-View-Controller) veya MVVM (Model-View-ViewModel) gibi tasarım kalıplarını kullanırken, sıklıkla veri modeli sınıfları ve kullanıcı arayüzü (UI) sınıfları arasında uyumsuzluklarla karşılaşır. Özellikle, veri modeli sınıfları genellikle iş mantığını veya veritabanı şemasını yansıtırken, kullanıcı arayüzü sınıfları, kullanıcı etkileşimi ve görsel sunumla ilgili verileri içerebilir.
Adapter Pattern, bu iki farklı yapı arasında uyumsuzlukları gidermek için ideal bir çözüm sunar. ViewModel mapping için Adapter Pattern kullanırken genellikle şu adımları izleriz:
Örnek bir senaryo düşünelim: Bir e-ticaret uygulamasında, bir ürünün detaylarını göstermek için bir ViewModel sınıfına ihtiyacımız var. Ancak, veritabanında ürün bilgilerini temsil eden bir veri modeli sınıfı bulunuyor. Bu durumda, Adapter Pattern kullanarak bu iki yapı arasındaki uyumsuzluğu gideririz.
// Veritabanı sınıfı
public class ProductModel
{
public string Name { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
// Diğer özellikler...
}
// ViewModel sınıfı
public class ProductViewModel
{
public string Name { get; set; }
public string Price { get; set; }
// Diğer özellikler...
}
// Adapter sınıfı
public class ProductAdapter
{
public ProductViewModel Adapt(ProductModel model)
{
return new ProductViewModel
{
Name = model.Name,
Price = model.Price.ToString("C2"),
// Diğer özelliklerin dönüştürülmesi...
};
}
}
Bu örnekte, ProductAdapter sınıfı, ProductModel’den ProductViewModel’e dönüşümü gerçekleştirir. Böylece, kullanıcı arayüzü kodu, ViewModel sınıflarını kullanarak verileri doğrudan gösterebilir ve Adapter sınıfı, veri modeli sınıflarından gelen veriyi ViewModel sınıflarına uygun hale getirir. Bu sayede, ViewModel’ler veritabanı yapılarından bağımsız hale gelir ve kullanıcı arayüzü kodunun daha modüler ve esnek olmasını sağlar.
Observer Pattern, bir nesnenin durumunda değişiklik olduğunda, bağımlı olan diğer nesnelere bu değişiklikleri bildirmek için kullanılan bir tasarım desenidir. Bu desen, yayınlayıcı-tüketici modeli olarak da bilinir ve sıklıkla yayın/abone veya gözlemci/abone modeli olarak adlandırılır.
Observer Pattern’ın temelinde bir yayınlayıcı (subject) ve bir veya daha fazla gözlemci (observer) bulunur. Yayınlayıcı, gözlemcilerine kendi durumu hakkında bilgi verir ve durumunda bir değişiklik olduğunda onları günceller. Gözlemciler, yayınlayıcının değişikliklerini takip eder ve gerekli aksiyonları alırlar.
Bu desenin ana bileşenleri şunlardır:
Observer Pattern’ın uygulanması, genellikle aşağıdaki adımları içerir:
Observer Pattern, MVC (Model-View-Controller), MVVM (Model-View-ViewModel) gibi tasarım kalıplarında sıklıkla kullanılır. Özellikle kullanıcı arayüzü bileşenlerinin durumunu izlemek ve güncellemek için ideal bir desendir. Örneğin, bir modelin durumu değiştiğinde, bu değişikliklerin otomatik olarak kullanıcı arayüzüne yansıtılması için Observer Pattern kullanılabilir.
Bu desenin uygulama alanları şunlardır:
Observer Pattern’ı uygulamak için C#’da basit bir olay (event) ve delegeler kullanarak bir gözlemci (observer) yapılandırabiliriz. Bir yayınlayıcı (subject) nesne, gözlemcilere (observer) kaydolabilir ve durumu değiştiğinde gözlemcilere haber verebilir.
Bu kavramı basit bir örnekle açıklayalım:
Öncelikle, bir yayınlayıcı (subject) sınıfı oluşturalım:
using System;
public class Subject
{
// Olay (event) ve delegeleri tanımlayalım
public event EventHandler StateChanged;
// Yayınlayıcının durumu
private string state;
public string State
{
get { return state; }
set
{
state = value;
// Durum değiştiğinde olayı tetikleyelim
OnStateChanged();
}
}
// Olayı tetikleyen yöntem
protected virtual void OnStateChanged()
{
StateChanged?.Invoke(this, EventArgs.Empty);
}
}
Bu sınıfta, StateChanged
adında bir olay (event) ve StateChanged
adında bir delegede tanımladık. State
adında bir özellik tanımladık ve bu özellik değiştiğinde OnStateChanged
metodunu çağırarak olayı tetikler.
Şimdi, bir gözlemci (observer) sınıfı oluşturalım:
using System;
public class Observer
{
public void Subscribe(Subject subject)
{
// Yayınlayıcıdaki olaya abone olalım
subject.StateChanged += HandleStateChanged;
}
public void Unsubscribe(Subject subject)
{
// Aboneliği iptal edelim
subject.StateChanged -= HandleStateChanged;
}
private void HandleStateChanged(object sender, EventArgs args)
{
// Yayınlayıcının durumu değiştiğinde bu metod tetiklenecek
Console.WriteLine("State changed!");
}
}
Bu sınıf, Subscribe
ve Unsubscribe
adında iki yöntem içerir. Subscribe
yöntemi, bir yayınlayıcıdaki olaya abone olurken Unsubscribe
yöntemi ise aboneliği iptal eder. HandleStateChanged
yöntemi, yayınlayıcının durumu değiştiğinde tetiklenecek olan yöntemdir.
Şimdi, bu sınıfları kullanarak bir örnek oluşturalım:
class Program
{
static void Main(string[] args)
{
// Yayınlayıcı ve gözlemci oluşturalım
Subject subject = new Subject();
Observer observer = new Observer();
// Gözlemci, yayınlayıcıdaki olaya abone olsun
observer.Subscribe(subject);
// Yayınlayıcının durumunu değiştirelim
subject.State = "New State";
// Aboneliği iptal edelim
observer.Unsubscribe(subject);
// Yayınlayıcının durumunu tekrar değiştirelim
subject.State = "Another State";
}
}
Bu örnekte, bir yayınlayıcı ve bir gözlemci oluşturduk. Gözlemci, yayınlayıcıdaki olaya abone oldu ve yayınlayıcının durumu değiştiğinde haberdar oldu. Daha sonra, aboneliği iptal ettik ve tekrar durumu değiştirdiğimizde gözlemcinin bu değişiklikten haberi olmadı. Bu, Observer Pattern’ın basit bir uygulamasını göstermektedir.
INotifyPropertyChanged arabirimi (interface), C# ve .NET platformunda model sınıflarının durum değişikliklerini gözlemlemek için kullanılan bir mekanizmadır. Bu arabirim, Observer Pattern’ın bir uygulaması olarak düşünülebilir ve genellikle MVVM (Model-View-ViewModel) mimarisinde kullanılır. MVVM’de, View (kullanıcı arayüzü), ViewModel’lerin durum değişikliklerini dinler ve bu değişiklikleri kullanıcı arayüzünde günceller.
INotifyPropertyChanged arabirimi, .NET Framework’un System.ComponentModel
ad alanında bulunur. Bu arabirim, sınıfın durumunda bir değişiklik olduğunda bir olay (event) fırlatmak için bir mekanizma sağlar. Bu olay, nesnenin durumu değiştiğinde tüketicilere (gözlemcilere) haber verilmesini sağlar.
INotifyPropertyChanged arabiriminin temel metodu PropertyChanged
olayını tanımlar. Bu olay, sınıfın bir özelliği değiştiğinde tetiklenir ve bu değişikliği dinleyen tüm tüketicilere haber verilir.
Aşağıda, INotifyPropertyChanged arabirimini kullanarak bir model sınıfının durum değişikliklerini nasıl gözlemleyebileceğinizi gösteren bir örnek var:
using System;
using System.ComponentModel;
public class Person : INotifyPropertyChanged
{
private string name;
// Ad özelliği
public string Name
{
get { return name; }
set
{
if (name != value)
{
name = value;
// PropertyChanged olayını tetikleyelim
OnPropertyChanged("Name");
}
}
}
// PropertyChanged olayı tanımlama
public event PropertyChangedEventHandler PropertyChanged;
// PropertyChanged olayını tetikleyen yardımcı metot
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
class Program
{
static void Main(string[] args)
{
// Model nesnesi oluşturalım
Person person = new Person();
// PropertyChanged olayına abone olalım
person.PropertyChanged += HandlePropertyChanged;
// Modelin durumunu değiştirelim
person.Name = "Alice";
}
// PropertyChanged olayını dinleyen metot
static void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine($"Property '{e.PropertyName}' changed");
}
}
Bu örnekte, Person
sınıfı INotifyPropertyChanged
arabirimini uygular. Name
özelliğinin set
erişimcisinde, özelliğin değeri değiştiğinde OnPropertyChanged
metodu çağrılır ve PropertyChanged
olayı tetiklenir. Main
metodu içinde, Person
nesnesinin PropertyChanged
olayına abone oluruz. Ardından, Name
özelliğinin değerini değiştirdiğimizde, bu değişikliğin dinlendiği HandlePropertyChanged
metodu çağrılır.
INotifyPropertyChanged arabirimi, genellikle kullanıcı arayüzü bileşenlerinin (örneğin, WPF veya WinForms gibi) ViewModel sınıflarının durum değişikliklerini dinlemek için kullanılır. Bu arabirim, bir nesnenin durum değişikliklerini gözlemlemek ve bu değişiklikleri diğer bileşenlere (örneğin, kullanıcı arayüzü) iletmek için mükemmel bir mekanizma sağlar. Bu sayede, MVVM modeli içinde model sınıflarının ve kullanıcı arayüzünün (View) birbirinden bağımsız hale gelmesi sağlanır.
Builder Pattern, nesne oluşturma sürecini ayrı bir sınıf üzerinden yürüten ve karmaşık nesnelerin adım adım oluşturulmasını sağlayan bir tasarım desenidir. Builder Pattern, nesne oluşturma sürecini bir yapılandırma adım kümesine böler ve bu adımların sırasını ve gerçekleştirilmesini kontrol eder. Bu sayede, karmaşık nesnelerin oluşturulması daha modüler ve esnek hale gelir.
Builder Pattern’ın temel amacı, bir nesnenin oluşturulması için gerekli adımları kapsüle etmektir. Bu desen genellikle karmaşık nesnelerin oluşturulması sırasında kullanılır ve aşağıdaki durumlar için uygundur:
Builder Pattern, genellikle bir ürün sınıfı ve bu ürünün oluşturulması için bir builder sınıfı olmak üzere iki temel bileşenden oluşur:
Builder Pattern, nesne oluşturma sürecini müşteriden gizler ve nesnenin nasıl oluşturulduğu ile ilgilenmez. Bu, karmaşık nesnelerin oluşturulması sürecini kolaylaştırır ve genellikle nesnelerin değişen yapısına uyum sağlamak için kullanılır.
Özetle, Builder Pattern, karmaşık nesnelerin adım adım oluşturulması ve bu oluşturma sürecinin yapısal bir şekilde yönetilmesi için kullanılan bir tasarım desenidir. Bu desen, nesne oluşturma sürecini modüler ve esnek hale getirir, böylece farklı varyasyonlara sahip nesnelerin oluşturulmasını sağlar.
Builder Pattern’ın C# dilinde basit bir uygulamasını oluşturalım. Bu örnekte, bir pizza siparişi oluşturmak için Builder Pattern kullanacağız.
İlk adım olarak, bir pizza sınıfı oluşturalım:
public class Pizza
{
public string Size { get; set; }
public bool Cheese { get; set; }
public bool Pepperoni { get; set; }
public bool Jalapenos { get; set; }
public override string ToString()
{
return $"Pizza: {Size}, Cheese: {Cheese}, Pepperoni: {Pepperoni}, Jalapenos: {Jalapenos}";
}
}
Şimdi, Builder Pattern’ı uygulamak için bir pizza yapıcı (builder) sınıfı oluşturalım:
public class PizzaBuilder
{
private Pizza pizza;
public PizzaBuilder(string size)
{
pizza = new Pizza { Size = size };
}
public PizzaBuilder AddCheese(bool cheese)
{
pizza.Cheese = cheese;
return this;
}
public PizzaBuilder AddPepperoni(bool pepperoni)
{
pizza.Pepperoni = pepperoni;
return this;
}
public PizzaBuilder AddJalapenos(bool jalapenos)
{
pizza.Jalapenos = jalapenos;
return this;
}
public Pizza Build()
{
return pizza;
}
}
Builder sınıfımız, pizza nesnesinin oluşturulması için gerekli adımları tanımlar. Her adım, builder sınıfından çağrılabilir ve builder sınıfı kendisini döndürerek zincirleme bir arayüz sağlar.
Son olarak, Builder Pattern’ı kullanarak bir pizza oluşturalım:
class Program
{
static void Main(string[] args)
{
// Pizza yapıcı (builder) nesnesi oluşturalım
PizzaBuilder builder = new PizzaBuilder("Large");
// Pizza nesnesini oluşturalım
Pizza pizza = builder.AddCheese(true)
.AddPepperoni(true)
.AddJalapenos(false)
.Build();
// Pizza nesnesini yazdıralım
Console.WriteLine(pizza);
}
}
Bu örnekte, bir pizza nesnesi oluşturmak için Builder Pattern’ı kullandık. Pizza yapıcı (builder) nesnesi oluşturulduktan sonra, pizza özellikleri (peynir, pepperoni, jalapenos vb.) zincirleme olarak eklenir. Son olarak, Build
metodu çağrılarak pizza nesnesi oluşturulur.
Builder Pattern, karmaşık nesnelerin oluşturulması sürecini yönetmek için kullanışlı bir tasarım desenidir. Bu desen, nesne oluşturma sürecini modüler hale getirir ve farklı varyasyonlara sahip nesnelerin oluşturulmasını kolaylaştırır.
deseni, bir uygulamanın yapılandırma ve başlatma süreçlerini yönetmek için kullanılan bir tasarım desenidir. Bu desen genellikle büyük ölçekli veya kurumsal düzeydeki MVC (Model-View-Controller) veya Web API uygulamalarında kullanılır.
ApplicationBuilderApplicationBuilder
deseni, uygulama başlatma sürecini parçalara ayırarak, yapılandırılabilir ve genişletilebilir bir yapı oluşturmayı amaçlar.
Bir kurumsal MVC uygulamasında ApplicationBuilder
deseninin nasıl kullanılabileceğini anlamak için aşağıdaki temel bileşenleri ele alabiliriz:
ApplicationBuilder
sınıfı, başlatma sürecini kontrol eden yöntemleri içerir. Bu yöntemler, arka planda farklı bileşenlerin yüklenmesi, yapılandırılması ve başlatılması gibi işlemleri gerçekleştirir.ApplicationBuilder
, uygulama başlatma sürecinde kullanılacak hizmetlerin yönetimini sağlar. IServiceProvider
, uygulama içindeki hizmetlerin (servislerin) oluşturulması ve sağlanması için bir arayüz sağlar. Bu, bağımlılık enjeksiyonu (dependency injection) ve servis bağlamı (service container) gibi kavramları içerir.ApplicationBuilder
sınıfını genişletmek için kullanılan uzantı yöntemlerini içerir. Özel middleware’lerin eklenmesi, yapılandırılması veya yönetilmesi gibi işlevler burada tanımlanabilir.Startup
sınıfı, uygulamanın başlatılması ve yapılandırılması için gereken tüm kodu içerir. Startup
sınıfı, uygulamanın yapılandırması, hizmetlerin kaydedilmesi, middleware’lerin eklenmesi ve başlatılması gibi adımları içeren ConfigureServices
ve Configure
yöntemlerini içerir.Kurumsal bir MVC uygulamasında, ApplicationBuilder
deseni, uygulamanın başlatılması ve yapılandırılmasını daha modüler ve yapılandırılabilir hale getirir. Bu desen, farklı ortamlar veya gereksinimler için uygulamanın başlatılma sürecini esnek hale getirir ve her bir adımın kontrolünü sağlar.
Özetle, ApplicationBuilder
deseni, büyük ölçekli veya kurumsal düzeydeki MVC veya Web API uygulamalarında uygulamanın başlatılması ve yapılandırılmasını yönetmek için kullanılan bir tasarım desenidir. Bu desen, uygulamanın başlatılma sürecini modüler hale getirir, yapılandırılabilirliği artırır ve uygulama bileşenlerinin bağımlılıklarını azaltır.
Aşağıda C# dilinde ApplicationBuilder
desenini kullanarak basit bir uygulamanın başlatılması ve yapılandırılması için kod örnekleri bulunmaktadır.
Öncelikle, ApplicationBuilder
sınıfını ve Startup
sınıfını tanımlayalım:
using System;
public class ApplicationBuilder
{
private readonly IServiceProvider _serviceProvider;
public ApplicationBuilder(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void Start()
{
// Başlatma süreci
Console.WriteLine("Application is starting...");
var startup = (Startup)_serviceProvider.GetService(typeof(Startup));
startup.ConfigureServices();
startup.Configure();
Console.WriteLine("Application has started.");
}
}
public class Startup
{
private readonly IServiceCollection _services;
public Startup(IServiceCollection services)
{
_services = services;
}
public void ConfigureServices()
{
// Servislerin kaydedilmesi
Console.WriteLine("Configuring services...");
_services.AddSingleton<IMyService, MyService>();
}
public void Configure()
{
// Middleware'lerin eklenmesi
Console.WriteLine("Configuring middleware...");
var myService = (IMyService)_services.BuildServiceProvider().GetService(typeof(IMyService));
myService.DoSomething();
}
}
public interface IMyService
{
void DoSomething();
}
public class MyService : IMyService
{
public void DoSomething()
{
Console.WriteLine("Doing something...");
}
}
Bu kod örneğinde, ApplicationBuilder
ve Startup
sınıfları tanımlanmıştır. ApplicationBuilder
sınıfı, uygulamanın başlatılması için gereken adımları içerir. Startup
sınıfı ise, uygulamanın yapılandırılması için gereken adımları içerir.
Son olarak, bu sınıfları kullanarak uygulamanın başlatılması işlemi gerçekleştirilir:
using Microsoft.Extensions.DependencyInjection;
class Program
{
static void Main(string[] args)
{
// Hizmetlerin kaydedilmesi
var services = new ServiceCollection();
var serviceProvider = services.BuildServiceProvider();
// ApplicationBuilder'ın oluşturulması ve başlatılması
var appBuilder = new ApplicationBuilder(serviceProvider);
appBuilder.Start();
}
}
Bu kod örneğinde, IServiceCollection
kullanarak uygulama hizmetlerinin kaydedilmesi gerçekleştirilir. Daha sonra, ApplicationBuilder
sınıfı oluşturulur ve başlatılır. Başlatma işlemi sırasında Startup
sınıfındaki ConfigureServices
ve Configure
yöntemleri sırasıyla çağrılır.
Bu şekilde, ApplicationBuilder
desenini kullanarak bir uygulamanın başlatılması ve yapılandırılması işlemi yapılmış olur. Bu desen, uygulamanın başlatılma sürecini modüler hale getirir, yapılandırılabilirliği artırır ve uygulama bileşenlerinin bağımlılıklarını azaltır.
Builder deseninin MVC uygulamalarında kullanımını anlamak için, bir örnek uygulama oluşturabiliriz. Bu örnekte, bir MVC uygulamasında bir öğrenci kaydı oluşturma işlemini ele alacağız ve Builder desenini kullanarak bu işlemi gerçekleştireceğiz.
Öğrenci Sınıfı (Product):
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public string Department { get; set; }
}
StudentBuilder Sınıfı (Builder):
public class StudentBuilder
{
private Student _student;
public StudentBuilder()
{
_student = new Student();
}
public StudentBuilder WithName(string name)
{
_student.Name = name;
return this;
}
public StudentBuilder WithAge(int age)
{
_student.Age = age;
return this;
}
public StudentBuilder WithDepartment(string department)
{
_student.Department = department;
return this;
}
public Student Build()
{
return _student;
}
}
Öğrenci Kaydı Servisi (Director):
public class StudentRegistrationService
{
private readonly StudentBuilder _builder;
public StudentRegistrationService(StudentBuilder builder)
{
_builder = builder;
}
public Student RegisterStudent(string name, int age, string department)
{
return _builder.WithName(name)
.WithAge(age)
.WithDepartment(department)
.Build();
}
}
Kontrolör (Controller):
public class StudentController : Controller
{
private readonly StudentRegistrationService _registrationService;
public StudentController(StudentRegistrationService registrationService)
{
_registrationService = registrationService;
}
[HttpPost]
public IActionResult CreateStudent(StudentViewModel model)
{
var student = _registrationService.RegisterStudent(model.Name, model.Age, model.Department);
// Öğrenci nesnesini veritabanına kaydet veya başka bir işlem yap
return Ok(student);
}
}
ViewModel (View Model):
public class StudentViewModel
{
public string Name { get; set; }
public int Age { get; set; }
public string Department { get; set; }
}
Bu şekilde, Builder desenini kullanarak bir MVC uygulamasında öğrenci kaydı oluşturma işlemini gerçekleştirebiliriz. StudentBuilder
sınıfı öğrenci nesnelerini adım adım oluştururken, StudentRegistrationService
servisi bu nesnelerin oluşturulma sürecini yönetir. Son olarak, StudentController
sınıfı istemci isteklerini işleyerek öğrenci kaydı oluşturur. Bu tasarım, uygulamanın genişlemesini ve bakımını kolaylaştırır ve karmaşık öğrenci nesnelerinin oluşturulmasını basitleştirir.
Command deseni, bir işlemi içeren bir nesneyi kapsülleyerek ve bu işlemi isteğe bağlı olarak yürüten bir yapı oluşturmayı amaçlar. Bu desen, bir işlemin yürütülme zamanını belirlerken, istemci kodunun ne zaman ve hangi işlemin gerçekleştirileceğini belirleme sorumluluğunu azaltır. Ayrıca, geri al (undo) işlemlerini desteklemek ve işlemleri sıraya almak gibi ekstra yetenekler de sağlar.
Command deseninin temel unsurları şunlardır:
Execute
metodu gibi bir işlemi yürütme yöntemini içerir.Command deseni, işlemleri bir nesne aracılığıyla temsil ederek kodun daha modüler ve esnek olmasını sağlar. Ayrıca, geri al ve işlemleri sıraya alma gibi özellikleri kolayca uygulamayı mümkün kılar.
Özetle, Command deseni, bir işlemi içeren bir nesneyi kapsülleyerek ve bu işlemi isteğe bağlı olarak yürüten bir yapı oluşturur. Bu desen, uygulamanın modülerliğini artırır, geri al işlemlerini kolaylaştırır ve işlemleri sıraya alma gibi ekstra yetenekler sağlar.
Command desenini basit bir şekilde C# ile nasıl uygulayabileceğimizi görelim.
Command (Komut): İşlemi temsil eden bir arayüz veya soyut sınıf olarak tanımlanır.
public interface ICommand
{
void Execute();
}
ConcreteCommand (Somut Komut): Command arayüzünü uygular ve belirli bir işlemi gerçekleştirmek için gerekli mantığı sağlar.
public class ConcreteCommand : ICommand
{
private Receiver _receiver;
public ConcreteCommand(Receiver receiver)
{
_receiver = receiver;
}
public void Execute()
{
_receiver.Action();
}
}
Receiver (Alıcı): Bir işlemi gerçekten yürüten nesneyi temsil eder.
public class Receiver
{
public void Action()
{
Console.WriteLine("Receiver: Action executed");
}
}
Invoker (Çağırıcı): Bir komutun yürütülme taleplerini alır ve bu talepleri gerçekleştirmek için gerekli komut nesnesini çağırır.
public class Invoker
{
private ICommand _command;
public void SetCommand(ICommand command)
{
_command = command;
}
public void ExecuteCommand()
{
_command.Execute();
}
}
Client (İstemci): Komut nesnelerini oluşturur ve çağırıcıya ileterek işlemleri yürütür.
class Program
{
static void Main(string[] args)
{
// Alıcı oluştur
var receiver = new Receiver();
// Komut oluştur ve alıcıyı belirt
var command = new ConcreteCommand(receiver);
// Çağırıcı oluştur ve komutu ayarla
var invoker = new Invoker();
invoker.SetCommand(command);
// Komutu yürüt
invoker.ExecuteCommand();
}
}
Bu basit örnekte, Command desenini kullanarak bir işlemi temsil eden bir arayüz (ICommand) tanımladık. Ardından, bu arayüzü uygulayan bir ConcreteCommand sınıfı oluşturduk. Receiver sınıfı, gerçek işlemleri gerçekleştiren nesneyi temsil ederken, Invoker sınıfı komutları alır ve yürütür. Son olarak, Program sınıfında bu bileşenleri bir araya getirerek işlemi gerçekleştirdik.
Bu örnek, Command deseninin temel prensiplerini göstermektedir. Command deseni, işlemleri nesneler aracılığıyla temsil ederek kodun daha modüler ve esnek olmasını sağlar.
Bir Command deseninin bir C# MVC uygulamasında nasıl kullanılabileceğini anlamak için, bir örneği ele alalım: Veri güncelleme işlemleri.
Command (Komut): Veri güncelleme işlemini temsil eden bir arayüz veya soyut sınıf olarak tanımlanır.
public interface ICommand
{
void Execute();
}
ConcreteCommand (Somut Komut): Command arayüzünü uygular ve belirli bir veri güncelleme işlemini gerçekleştirmek için gerekli mantığı sağlar.
public class UpdateDataCommand : ICommand
{
private readonly IDataService _dataService;
private readonly int _id;
private readonly string _newData;
public UpdateDataCommand(IDataService dataService, int id, string newData)
{
_dataService = dataService;
_id = id;
_newData = newData;
}
public void Execute()
{
_dataService.UpdateData(_id, _newData);
}
}
Receiver (Alıcı): Veri güncelleme işlemini gerçekleştiren hizmeti temsil eder.
public interface IDataService
{
void UpdateData(int id, string newData);
}
public class DataService : IDataService
{
public void UpdateData(int id, string newData)
{
// Veri güncelleme işlemini gerçekleştir
}
}
Invoker (Çağırıcı): Bir komutun yürütülme taleplerini alır ve bu talepleri gerçekleştirmek için gerekli komut nesnesini çağırır.
public class CommandInvoker
{
private ICommand _command;
public void SetCommand(ICommand command)
{
_command = command;
}
public void ExecuteCommand()
{
_command.Execute();
}
}
Kontrolör (Controller): Komut nesnelerini oluşturur ve Invoker’a ileterek işlemleri yürütür.
public class DataController : Controller
{
private readonly IDataService _dataService;
private readonly CommandInvoker _invoker;
public DataController(IDataService dataService, CommandInvoker invoker)
{
_dataService = dataService;
_invoker = invoker;
}
[HttpPost]
public IActionResult UpdateData(int id, string newData)
{
var updateCommand = new UpdateDataCommand(_dataService, id, newData);
_invoker.SetCommand(updateCommand);
_invoker.ExecuteCommand();
return RedirectToAction("Index");
}
}
Bu örnekte, Command desenini kullanarak bir MVC uygulamasında veri güncelleme işlemini ele aldık. UpdateDataCommand sınıfı, veri güncelleme işlemini gerçekleştiren bir komut sınıfıdır. IDataService arayüzü, veri hizmeti tarafından sağlanan bir alıcıdır ve veri güncelleme işlemini gerçekleştirir. CommandInvoker sınıfı, komutların çağrılmasını ve yürütülmesini yönetir. Son olarak, DataController sınıfı, veri güncelleme işlemini başlatır ve Invoker’a ileterek yürütülmesini sağlar.
Bu şekilde, Command desenini kullanarak MVC uygulamanızda veri güncelleme gibi işlemleri modüler ve esnek bir şekilde yönetebilirsiniz. Bu desen, karmaşık işlemleri basitleştirmek ve uygulamanızın bakımını kolaylaştırmak için güçlü bir araçtır.
Proxy deseni, bir nesnenin yerel veya uzak bir kaynağa erişimini kontrol etmek için kullanılan bir yapıdır. Bu desen, gerçek nesnenin yerine geçerek araya girer ve istemcinin nesneye doğrudan erişimini engeller veya kontrol eder. Temel amaç, gerçek nesnenin yaratılmasını ve yüklenmesini geciktirmek, istemci ve gerçek nesne arasında bir arayüz sağlamak, nesne üzerinde yetkilendirme veya güvenlik kontrolleri uygulamak veya nesne üzerinde ekstra işlevsellik sağlamaktır.
Proxy deseninin ana bileşenleri şunlardır:
Proxy deseninin uygulanması, aşağıdaki durumlarda faydalı olabilir:
Proxy deseni, gerçek nesneye erişimde bir ara katman sağlayarak uygulamayı modülerleştirmek, performansı artırmak ve güvenlik veya yetkilendirme kontrolleri uygulamak için ideal bir seçenektir.
Basit bir Proxy dosya erişimi örneği oluşturalım. Bu örnekte, bir dosyaya erişim sağlayan bir Proxy sınıfı ve gerçek dosya erişimini sağlayan bir RealSubject sınıfı oluşturacağız.
Subject (Konu): Dosyaya erişim için bir arayüz tanımlayalım.
public interface IFileAccess
{
string ReadFileContent();
}
RealSubject (Gerçek Konu): Dosyaya gerçek erişimi sağlayan sınıfı tanımlayalım.
using System.IO;
public class RealFileAccess : IFileAccess
{
private readonly string _filePath;
public RealFileAccess(string filePath)
{
_filePath = filePath;
}
public string ReadFileContent()
{
return File.ReadAllText(_filePath);
}
}
Proxy (Vekil): Dosyaya erişimi kontrol eden ve gerekirse ekstra işlemler ekleyen bir Proxy sınıfı oluşturalım.
public class FileProxy : IFileAccess
{
private readonly string _filePath;
private RealFileAccess _realFileAccess;
public FileProxy(string filePath)
{
_filePath = filePath;
}
public string ReadFileContent()
{
// Gerçek dosya erişimi sadece ilk çağrıldığında gerçekleştirilir
if (_realFileAccess == null)
{
_realFileAccess = new RealFileAccess(_filePath);
}
// Gerçek dosya erişimini çağırır ve sonucu döndürür
return _realFileAccess.ReadFileContent();
}
}
Kullanım:
class Program
{
static void Main(string[] args)
{
// Proxy aracılığıyla dosyaya erişim
IFileAccess fileProxy = new FileProxy("example.txt");
// Dosya içeriğini oku
string content = fileProxy.ReadFileContent();
Console.WriteLine(content);
}
}
Bu kod, Proxy desenini kullanarak bir dosyaya erişimi kontrol eden basit bir uygulamayı göstermektedir. RealFileAccess sınıfı gerçek dosya erişimini sağlarken, FileProxy sınıfı gerçek dosyaya erişimi kontrol eder. İlk çağrıldığında RealFileAccess sınıfı oluşturulur ve gerçek dosya erişimi gerçekleştirilir. Daha sonra aynı dosyaya erişim yapıldığında, gerçek dosya erişimi tekrar gerçekleşmez ve daha önce oluşturulmuş RealFileAccess nesnesi kullanılır. Bu şekilde, Proxy deseni gerçek dosya erişimini geciktirerek ve gerektiğinde ekstra işlevselliği sağlayarak dosya erişimini kontrol eder.
Caching data service proxy, bir veri hizmetine erişim sağlayan ve verileri bir önbellekte saklayarak tekrar eden istekler için gereksiz veri tabanı erişimini azaltan bir yapıdır. Bu desen, performansı artırmak ve veritabanı üzerindeki yükü azaltmak için kullanışlıdır. MVC uygulamasında bir caching data service proxy uygulamak için aşağıdaki adımları takip edebiliriz:
IDataService Arayüzü: Veri hizmetine erişim sağlamak için bir arayüz tanımlayalım.
public interface IDataService
{
string GetData(int id);
}
RealDataService Sınıfı: Gerçek veri hizmetine erişimi sağlayan bir sınıf oluşturalım.
public class RealDataService : IDataService
{
public string GetData(int id)
{
// Veritabanından veri al
return $"Data for ID {id} from database";
}
}
CachingDataServiceProxy Sınıfı: Veri erişimini kontrol eden ve gerektiğinde önbellekteki veriyi kullanarak gerçek veri hizmetine erişim sağlayan bir proxy sınıfı oluşturalım.
using System;
using System.Collections.Generic;
public class CachingDataServiceProxy : IDataService
{
private readonly IDataService _realDataService;
private readonly Dictionary<int, string> _cache;
public CachingDataServiceProxy(IDataService realDataService)
{
_realDataService = realDataService;
_cache = new Dictionary<int, string>();
}
public string GetData(int id)
{
// Önbellekte veri varsa, önbellekten veriyi döndür
if (_cache.ContainsKey(id))
{
return $"Data for ID {id} from cache: {_cache[id]}";
}
// Önbellekte veri yoksa, gerçek veri hizmetinden veriyi al ve önbelleğe ekle
var data = _realDataService.GetData(id);
_cache[id] = data;
return data;
}
}
Kontrolör (Controller): Veri hizmetine erişimi sağlayan bir kontrolör oluşturalım ve bu kontrolörde CachingDataServiceProxy kullanalım.
public class DataController : Controller
{
private readonly IDataService _dataService;
public DataController(IDataService dataService)
{
_dataService = new CachingDataServiceProxy(dataService);
}
public IActionResult GetData(int id)
{
var data = _dataService.GetData(id);
return View((object)data);
}
}
Bu şekilde, MVC uygulamasında bir caching data service proxy oluşturabiliriz. CachingDataServiceProxy sınıfı, gerçek veri hizmetine erişim sağlamak ve gerektiğinde önbellekteki veriyi kullanmak için kullanılır. Bu, veritabanı erişimini azaltarak uygulamanın performansını artırabilir ve veri tabanına olan yükü azaltabilir.
Chain of Responsibility deseni, bir dizi nesnenin (handler) istemci tarafından gönderilen isteği işleme fırsatına sahip olduğu bir davranışsal desendir. İsteği işleyebilecek nesne bulunana kadar bu zincir boyunca isteğin ilerlediği bir yapıdır. Her bir handler, isteği işleyip işleyemeyeceğini belirler ve işleyebilecekse işler, aksi halde isteği bir sonraki handler’a iletir.
Bu desenin temel amacı, istemciden gelen istekleri işleyen nesneler arasında bağlantıları gevşek tutarak istemci kodunun daha modüler, esnek ve yeniden kullanılabilir olmasını sağlamaktır. Ayrıca, bir isteğin hangi nesne tarafından işleneceğinin belirlenmesini sağlayarak, işleme sırasında dinamik olarak değişiklik yapılmasına olanak tanır.
Chain of Responsibility deseninin ana bileşenleri şunlardır:
Chain of Responsibility deseni, bir isteğin farklı işleyiciler tarafından farklı şekillerde işlenmesini sağlayarak, kodun daha modüler ve esnek olmasını sağlar. Ayrıca, yeni işleyiciler eklemek veya mevcut işleyicileri değiştirmek kolaydır, çünkü işleyici zinciri gevşek bağlıdır. Bu desen, özellikle isteğin işleyeceği işleyicinin dinamik olarak belirlendiği durumlarda faydalıdır.
Chain of Responsibility desenini, basit bir örnek olan exception handling (istisna işleme) senaryosu üzerinden açıklayalım.
Handler (İşleyici): İstisnaları işleyen arayüzü veya soyut sınıfı temsil eder.
public interface IExceptionHandler
{
void HandleException(Exception exception);
}
ConcreteHandler (Somut İşleyici): Handler arayüzünü veya soyut sınıfını uygular ve belirli bir türdeki istisnaları işleyebilecek nesneyi temsil eder.
public class LoggingExceptionHandler : IExceptionHandler
{
public void HandleException(Exception exception)
{
// Hata günlüğüne istisnayı kaydet
Console.WriteLine($"Logging Exception: {exception.Message}");
}
}
public class EmailExceptionHandler : IExceptionHandler
{
public void HandleException(Exception exception)
{
// E-posta göndererek istisnayı bildir
Console.WriteLine($"Sending Email Exception: {exception.Message}");
}
}
Client (İstemci): Bir istisnayı gönderen ve hangi işleyicinin istisnayı işleyeceğini bilmeyen kod parçasıdır. İstemci, istisnayı işleyebilecek bir işleyici zincirini başlatır ve istisnayı zincir boyunca iletir.
public class ExceptionHandlerChain
{
private readonly List<IExceptionHandler> _handlers;
public ExceptionHandlerChain()
{
_handlers = new List<IExceptionHandler>();
}
public void AddHandler(IExceptionHandler handler)
{
_handlers.Add(handler);
}
public void HandleException(Exception exception)
{
foreach (var handler in _handlers)
{
handler.HandleException(exception);
}
}
}
Kullanım:
class Program
{
static void Main(string[] args)
{
// İşleyici zinciri oluştur
var handlerChain = new ExceptionHandlerChain();
handlerChain.AddHandler(new LoggingExceptionHandler());
handlerChain.AddHandler(new EmailExceptionHandler());
try
{
// Örnek bir istisna oluştur
throw new InvalidOperationException("Invalid operation occurred!");
}
catch (Exception ex)
{
// İstisnayı işleyici zincirine ilet
handlerChain.HandleException(ex);
}
}
}
Bu örnekte, Chain of Responsibility desenini kullanarak basit bir exception handling mekanizması oluşturduk. İstemci, bir istisna oluşturur ve bu istisnayı işleyebilecek bir işleyici zincirini başlatır. Zincirdeki her işleyici, istisnayı işlemek için sorumludur. Eğer bir işleyici istisnayı işleyemezse, istisna bir sonraki işleyiciye iletilecektir. Bu şekilde, istisnaların işlenmesi için esnek bir yapı oluşturulur ve her işleyici istisnayı farklı şekillerde işleyebilir veya işleyici zinciri kolayca değiştirilebilir.
ASP.NET Core Request Pipeline’i Chain of Responsibility desenine benzer bir şekilde modelleyebiliriz. Bu, gelen HTTP isteğinin işlenmesi için bir dizi bileşenin (middleware) zincir halinde çalıştığı bir yapıya sahiptir. Her bir middleware, gelen isteği işler ve ardından isteği bir sonraki middleware’e iletir veya işlemi sonlandırır.
Handler (İşleyici): Middleware’leri temsil eder. Her bir middleware, gelen isteği işler ve isteği bir sonraki middleware’e iletir veya işlemi sonlandırır.
public interface IMiddleware
{
Task InvokeAsync(HttpContext context, RequestDelegate next);
}
ConcreteHandler (Somut İşleyici): Middleware’leri temsil eden sınıflardır. Her bir middleware, IMiddleware arayüzünü uygular ve gelen isteği işler.
public class LoggingMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// Gelen isteği işle
Console.WriteLine($"Logging Middleware: {context.Request.Path}");
// İsteği bir sonraki middleware'e ilet
await next(context);
}
}
public class AuthenticationMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// Gelen isteği doğrula
Console.WriteLine($"Authentication Middleware: {context.Request.Path}");
// İsteği bir sonraki middleware'e ilet
await next(context);
}
}
public class AuthorizationMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// Gelen isteği yetkilendir
Console.WriteLine($"Authorization Middleware: {context.Request.Path}");
// İsteği bir sonraki middleware'e ilet
await next(context);
}
}
Client (İstemci): ASP.NET Core uygulamasının başlangıç noktası olan Startup sınıfı, middleware’leri configure eder ve bir pipeline oluşturur.
public class Startup
{
public void Configure(IApplicationBuilder app)
{
// Middleware'leri pipeline'a ekleyerek bir zincir oluştur
app.UseMiddleware<LoggingMiddleware>();
app.UseMiddleware<AuthenticationMiddleware>();
app.UseMiddleware<AuthorizationMiddleware>();
// Son middleware'yi eklemeyi unutma (isteği işlemeyi sonlandırır)
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello, World!");
});
}
}
Bu şekilde, ASP.NET Core Request Pipeline’i, gelen HTTP isteğini işlemek için bir Chain of Responsibility desenine benzer bir yapı oluşturur. Her bir middleware, gelen isteği işler ve isteği bir sonraki middleware’e iletir. Bu sayede, işlem sırasında isteği farklı şekillerde işleyebilir ve middleware’lerin sırasını değiştirebiliriz.
ASP.NET Core Request Pipeline’ına bir filtre eklemek için, mevcut Chain of Responsibility yapısına bir ara katman eklememiz gerekecektir. Bu ara katman, gelen isteği işleyecek ve bir sonraki middleware’e iletecek, ancak bir filtreleme işlemi de yapacaktır.
Handler (İşleyici): Middleware’leri temsil eden arayüz veya soyut sınıf. Tüm middleware’ler bu arayüzü uygular.
public interface IMiddleware
{
Task InvokeAsync(HttpContext context, RequestDelegate next);
}
ConcreteHandler (Somut İşleyici): Middleware’leri temsil eden sınıflar. Her bir middleware, IMiddleware arayüzünü uygular ve gelen isteği işler.
public class LoggingMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// Gelen isteği işle
Console.WriteLine($"Logging Middleware: {context.Request.Path}");
// İsteği bir sonraki middleware'e ilet
await next(context);
}
}
public class AuthenticationMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// Gelen isteği doğrula
Console.WriteLine($"Authentication Middleware: {context.Request.Path}");
// İsteği bir sonraki middleware'e ilet
await next(context);
}
}
// Yeni eklenen filtre
public class CustomFilterMiddleware : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// İsteği filtrele
if (context.Request.Query.ContainsKey("filter"))
{
// Filtreleme işlemi
Console.WriteLine($"Custom Filter Middleware: Filtering request by {context.Request.Query["filter"]}");
}
// İsteği bir sonraki middleware'e ilet
await next(context);
}
}
Client (İstemci): ASP.NET Core uygulamasının başlangıç noktası olan Startup sınıfı, middleware’leri configure eder ve bir pipeline oluşturur.
public class Startup
{
public void Configure(IApplicationBuilder app)
{
// Middleware'leri pipeline'a ekleyerek bir zincir oluştur
app.UseMiddleware<LoggingMiddleware>();
app.UseMiddleware<AuthenticationMiddleware>();
// Yeni filtre middleware'ini pipeline'a ekleyin
app.UseMiddleware<CustomFilterMiddleware>();
// Son middleware'yi eklemeyi unutmayın (isteği işlemeyi sonlandırır)
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello, World!");
});
}
}
Bu şekilde, ASP.NET Core Request Pipeline’ına bir filtre eklemiş olduk. Yeni eklenen CustomFilterMiddleware, gelen isteği filtreler ve filtreleme işlemi gerçekleştirir. Daha sonra, işlemi bir sonraki middleware’e iletir. Bu sayede, gelen isteği işlemek için özelleştirilmiş bir filtre ekleyebilir ve middleware zincirine entegre edebiliriz.
Bir sonraki yazıda görüşmek dileğiyle!”