Object Oriented Programming etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Object Oriented Programming etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

C# Chain of Responsibility Pattern Kullanımı - OOP Design Pattern

Chain of Responsibility (Sorumluluk Zinciri) tasarım deseni behavior grubununa ait, bir isteğin belli sınıflar içinde gezdirilerek ilgili sınıfın işlem yapmasını yöneten tasarım desenidir. Chain of responsibility tasarım deseninin dofactory.com a göre kullanım sıklığı 40% lardadır.




Bu deseni anlamaya çalışırken bir çok nesne örneğinin Loosly Coupled (zayıf şekilde) bağlı olduğunu ve bunların bir zincir gibi dizildiğini düşünün. Personel, müdür, genel müdür gibi bir dizilimi buna örnek olarak verelebiliriz. Bir Workflow örneği düşünelim mesela: önce personel işi yapar, sonra müdürü onaylar, sonra genel müdür imza atar. Personel nesnesi işi tamamladıktan sonra işi müdür nesnesine gönderir. Daha sonra müdür nesnesi onaylama işini yapar ve işi genel müdür nesnesine gönderir ve böylece yapılacak iş zincirimizin son halkası olan genel müdür nesnesine gelmiştir ve genel müdür imzalama işini yaparak zinciri sonlandırır. Kısacası zincir içerisindeki nesne örnekleri söz konusu içeriği kendi işlerini yaptıktan sonra bir sonraki adıma gönderirler. Program çalışma mantığına göre istenilen bir yerde zincir sonlandırılabilir veya başa döndürülebilir.


Programlamada Event Based Programming'de sıkça kullanılır. Bir event'ın birden fazla nesne tarafından ele alınması gerektiği durumlarda bu deseni kullanabiliriz. Bu daha çok iç içe bileşenler içeren Form' larda veya diğer taşıyıcı(Container) kontrollerde görebiliriz. Örneğin; tüm formlar için ortak olan bir event tetiklendiğinde, bir zincir şekilde tüm formlar bu event'ı uygulamalıdır. Parent form -> Chield form 1 -> Chield form 2 şeklinde.

Şİmdi örnek olarak basit bir personel izin sistemi yazalım. Engineer -> Program Manager -> HR şeklinde izin onaylama zincirimizin olduğunu düşünerek bir program yazalım:

UML Diagram:


Kod:


    
    /// <summary>
    /// The 'Handler' abstract class
    /// </summary>
    public abstract class Employee
    {
        public Guid EmployeeId { get; set; }
        public int LeaveDays { get; set; }
        // approve edecek bir sonraki kisi
        public Employee NextApprover { get; set; }

        public Employee()
        {
            EmployeeId = Guid.NewGuid();
            LeaveDays = 15;
        }

        // Event tanimlaniyor
        public delegate void OnLeaveApplied(int requestedDays);
        public event OnLeaveApplied onLeaveApplied = null;

        public abstract void ApproveLeave(int requestedDays);

        // Using this we can apply for leave
        public void ApplyLeave(int requestedDays)
        {
            if (onLeaveApplied != null)
            {
                onLeaveApplied(requestedDays);
            }
        }
    }

    /// <summary>
    /// The 'ConcreteHandler' class
    /// </summary>
    public class Engineer:Employee
    {
        public Engineer()
        {
            this.onLeaveApplied += Engineer_onLeaveApplied;
        }

        private void Engineer_onLeaveApplied(int requestedDays)
        {
            if (NextApprover != null)
            {
                NextApprover.ApplyLeave(requestedDays);
            }
        }

        public override void ApproveLeave(int requestedDays)
        {
            Console.WriteLine(@"Engineer does not have
                       approve permission.");
        }
    }
    /// <summary>
    /// The 'ConcreteHandler' class
    /// </summary>
    public class ProgramManager:Employee
    {
        public ProgramManager()
        {
            this.onLeaveApplied += ProgramManager_onLeaveApplied;
        }

        private void ProgramManager_onLeaveApplied(int requestedDays)
        {
            ApproveLeave(requestedDays);
            if (NextApprover != null)
                NextApprover.ApplyLeave(requestedDays);
        }

        // If we can process lets show the output
        public override void ApproveLeave(int requestedDays)
        {
            Console.WriteLine(@"EmployeeId: {0} Requested Days: {1} 
                 Approve: {2}",
                this.EmployeeId, requestedDays, "ProgramManager");
        }
    }
    /// <summary>
    /// The 'ConcreteHandler' class
    /// </summary>
    public class HR:Employee
    {
        public HR()
        {
            this.onLeaveApplied += HR_onLeaveApplied;
        }

        private void HR_onLeaveApplied(int requestedDays)
        {
            ApproveLeave(requestedDays);
            if (NextApprover != null)
                NextApprover.ApplyLeave(requestedDays);
        }

        // If we can process lets show the output
        public override void ApproveLeave(int requestedDays)
        {
            Console.WriteLine(@"EmployeeId: {0} Requested Days: {1} 
                 Approve: {2}",
                this.EmployeeId, requestedDays, "HR");
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            Engineer engineer = new Engineer();
            ProgramManager programManager = new ProgramManager();
            HR hr = new HR();

            //workflow u olusturuyoruz
            engineer.NextApprover = programManager;
            programManager.NextApprover = hr;

            engineer.ApplyLeave(3);

            Console.ReadLine();
        }

    }

Çıktı:








C# Visitor Pattern Kullanımı - OOP Design Pattern

Visitor tasarım deseni (ziyaretçi tasarım deseni), behavioral grubuna ait bir tasarım desenidir. Uygulamada ki sınıflara yeni metotlar eklenmesini düzenleyen bir tasarım desenidir. Dofactory.com a göre kullanım sıklığı 20% civarındadır.



Yukarıda belirttiğimiz gibi uygulamaya yetni metotlar eklemesini düzenleyen bir tasarım desenidir Visitor tasarım deseni. Örneğin uygulamamıza bir metot eklemek istiyoruz bu durumda sınıfların uyguladığı arayüze ve bu arayüzü uygulayan sınıflara metot yazılır veya eklenmesi gereken sınıflara eklenir. Arayüze eklersek bu arayüzü uygulayan tüm sınıflara gerekli olsada olmasada eklemek zorunda kalırız. Bu da tasarım prensiplerine aykırı bir haraket olacaktır. Eklenmesi gereken tüm sınıflara tek tek eklersekte kodun anlaşılırlığı bozulacaktır ayrıca bakımıda zorlaşacaktır; metotta bir değişiklik yapılmak istense tüm sınıflardaki metotlar tek tek update edilmesi gerekecektir. Her yeni ihtiyaç için yeni visitor sınıfları yazıp bunu sınıfımızın kullanmasını sağlayarak bu durumları Visitor tasarım deseni ile ortadan kaldırabiliriz.


Örneğimizide şu şekilde tasarlayalım: Mesela bir tablet sınıfımız var ve bu sınıftan türeyen bazı tabletlerin wifi özelliği var bazılarının yok aynı şekilde bir kısmının 3G özelliği var bir kısmının yok. Böyle olunca tabletlerin türetildiği tablet abstract sınıfına WifiAc(), 3GAc() gibi metot tanımlamamız çok saçma olur. Çünkü Wifi özelliği olmayan bir tablette bu metodu kullanabilir olur böyle olunca. Diğer bir yöntemde wifisi olan sınıfları bulup tek tek wifi açma metodunu eklemek ama buda kodu çok anlaşılmaz hale getirecektir. Aynı zamanda sınıfımıza başka bir özellik eklemek istediğimizde yine sınıfımıza müdahale etmek zorunda kalırız. Bu durumu ortadan kaldırmak için istenilen işleri yapan visitor sınıfları yazıp Accept metodu ile bu sınıfların içerisindeki metodları istediğimiz sınıflar için çalıştırabiliriz. Örnek:

UML Diyagramı:





Kod:

    /// <summary>
    /// The 'Tablet' abstract class
    /// </summary>
    public abstract class Tablet
    {
        public string Model { get; set; }
        public string Brand { get; set; }

        public Tablet(string model, string brand)
        {
            Model = model;
            Brand = brand;
        }

        public abstract void Accept(IVisitor visitor);
    }

    /// <summary>
    /// The 'ConcreteElement' class
    /// </summary>
    public class IPad:Tablet
    {
        public IPad(string model, string brand)
            : base(model, brand)
        {
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// The 'ConcreteElement' class
    /// </summary>
    public class GalaxyTab:Tablet
    {
        public GalaxyTab(string model, string brand)
            : base(model, brand)
        {
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// The 'Visitor' interface
    /// </summary>
    public interface IVisitor
    {
        void Visit(Tablet tablet);
    }

    /// <summary>
    /// A 'ConcreteVisitor' class
    /// </summary>
    public class WifiVisitor:IVisitor
    {
        public void Visit(Tablet tablet)
        {
            if (tablet is IPad)
                Console.WriteLine("Ipad wifi has open.");
            else if (tablet is GalaxyTab)
                Console.WriteLine("GalaxyTab does not have wifi option.");
            else
                Console.WriteLine("This object is not a tablet.");
        }
    }

    /// <summary>
    /// A 'ConcreteVisitor' class
    /// </summary>
    public class ThreeGVisitor:IVisitor
    {
        public void Visit(Tablet tablet)
        {
            if (tablet is IPad)
                Console.WriteLine("Ipad wifi does not have 3G option.");
            else if (tablet is GalaxyTab)
                Console.WriteLine("GalaxyTab 3G has open.");
            else
                Console.WriteLine("This object is not a tablet.");
        }
    }

        static void Main(string[] args)
        {
            IPad iPad = new IPad("Ipad mini", "Apple");
            GalaxyTab galaxyTab = new GalaxyTab("Galaxy Tab", "Samsung");

            iPad.Accept(new WifiVisitor());
            galaxyTab.Accept(new WifiVisitor());

            iPad.Accept(new ThreeGVisitor());
            galaxyTab.Accept(new ThreeGVisitor());

        //bunun gibi baska visitor sınıfları yazarak sınıfımızı değiştirmeden
        //yeni metotlar çalıştırabilir hale getirebiliriz. 

            Console.ReadLine();

        }
Çıktı:






C# State Pattern Kullanımı - OOP Design Pattern

State tasarım deseni behavior grubununa ait, nesnelerin farklı durumlarda farklı çalışmalarını düzenleyen bir tasarım desenidir. dofactory.com sitesine göre kullanım sıklığı %60 civarındadır.



Örneğin bir kahve makinası düşünün önce duğmesine basarız hazırlanıyor yazar ekranda bu makinanın hazırlanıyor durumuna geçtiğini gösterir bu durumda su kaynatılır kahve eklenir. Ardından kahve hazırdır bardağa boşaltma kısmı gelir. Bu durumda kahve bardağa boşaltılır bitirme durumundadır makina bu sefer. Görüldüğü gibi makina farklı durumlarda farklı işlemler yapmaktadır. Bu patternin amacıda bunun gibi nesnenin farklı durumlarında farklı çalışmaların yapılmasını sağlamaktır.

Bir başka örnek bankacılık sektöründen verilebilir mesela bir müşterinin hesabındaki parası bir sınırı geçince gold müşteri statüsünde olacaktır ve verilen faiz oranı değişecektir. Bu durumda da bu pattern kullanılabilir.

Örnek kodumuzu basit bir server otomasyonu yaparak yazmayı düşündüm. Örnekte contex nesnemiz olarak bir server’ımız var ve CPU değeri %80 in üzerine çıkınca status OverloadState durumuna geliyor ve bu statüde iken yeniden stabil duruma geçmek için bir takım programları kapatıyor ve yeniden stabil olunca ise OKState durumuna geçiyor.

UML Şema:

Kod:
     /// 
    /// State abstract class
    /// 
    public abstract class ServerState
    {
        public abstract void HandleState(Server context);
    }

    /// 
    /// Concrete State
    /// 
    public class OverloadState:ServerState
    {
        public override void HandleState(Server context)
        {
            Console.WriteLine(@"Server CPULevel is: {0}. Server state 
                 is overload. Some programs is closing.", context.CPULevel);
            context.CloseProgram(5);
            if (context.CPULevel > 80)
                context.State = new OverloadState();
            else
                context.State = new OkState();
        }
    }

    /// 
    /// Concrete State
    /// 
    public class OkState:ServerState
    {
        public override void HandleState(Server context)
        {
            Console.WriteLine(@"Server CPULevel is: {0}. Server state 
                   is OK."
                   ,context.CPULevel);
        }
    }

/// 
    /// Context class
    /// 
    public class Server
    {
        public int CPULevel { get; set; }

        private ServerState _state;
        public ServerState State
        {
            get { return _state; }
            set
            {
                _state = value;
                // Burada durum değişimleri sonucu çalıştırılacak 
                // davranışların başlatılma noktasınıda 
                // merkezileştirmiş oluyoruz.
                _state.HandleState(this);
            }
        }

        public Server()
        {
            this.CPULevel = 50;
            ControlServerCPULevel();
        }

        public void ControlServerCPULevel()
        {
            if (this.CPULevel > 80)
                this.State = new OverloadState();
            else
                this.State = new OkState();
        }

        public void CloseProgram(int programUsageCPU)
        {
            this.CPULevel -= programUsageCPU;
        }

        public void AddProgram(int programUsageCPU)
        {
            this.CPULevel += programUsageCPU;
            ControlServerCPULevel();
        }
    }

        static void Main(string[] args)
        {
            Server server = new Server();
            server.AddProgram(20);
            server.AddProgram(10);
            server.AddProgram(30);

            Console.ReadLine();

        }


Çıktı:

C# Mediator Pattern Kullanımı - OOP Design Pattern

Mediator design pattern (aracı tasarım deseni), behavior grubununa ait, çalışmaları birbirleri ile aynı arayüzden türeyen nesnelerin durumlarına bağlı olan nesnelerin davranışlarını düzenleyen tasarım desenidir. dofactory.com a göre kullanım oranı %40 civarındadır.


Anlaşılması zor ve karmaşık yapılarda aracı nesne olarak kullanılır. Bir çok nesne birbirleriyle iletişime geçmek yerine sadece bu aracı nesne ile bağlanırlar. Buda yapılan tüm karmaşık faaliyetleri gizler ve kullanıcıların etkileşimleri, sistemi daha rahat anlamasını sağlar.


Kısaca mediator tasarım deseni birbirleri ile ilişkili olan bu nesneler arasında ki iletişimin ana bir nesne üzerinden (mediator) yapılmasını sağlar. Böylece nesneler arasındaki bağ zayıflatılır ve geliştirme aşamasında kod karmaşasını önler ve kodun yönetilmesini kolaylaştırır.


İnternette dolaşan popular bir örnek var havaalanı ile ilgili havaalanı olmasa uçaklar ben şimdi iniyorum kimse inmesin gibi birbirleriyle konuşsalar oluşacak kaosu bir düşünün işte burada havaalanı mediator tasarım deseninin görevini üstlenerek uçakları tek bir yerden yönetiyor. Şimdi bu örneği koda dökelim:

UML Şeması:


Kod: 

/// <summary>
    /// Mediator
    /// </summary>
    public interface IAirport
    {
        void Register(AirlineBase airline);
        bool GiveLandingPermission(string flightCode);
    }

    /// <summary>
    /// Concrete Mediator
    /// </summary>
    public class AtaturkAirport:IAirport
    {
        private Dictionary<string, AirlineBase> _planes;

        public AtaturkAirport()
        {
            _planes = new Dictionary<string, AirlineBase>();
        }

        public void Register(AirlineBase airline)
        {
            if (!_planes.ContainsValue(airline))
                _planes.Add(airline.FlightCode, airline);

            airline.Airport = this;
        }

        public bool GiveLandingPermission(string flightCode)
        {
            if (_planes.ContainsKey(flightCode))
                return true;
            else
                return false;
        }
    }
    /// <summary>
    /// Collague
    /// </summary>
    public abstract class AirlineBase
    {
        public string FlightCode { get; set; }
        public IAirport Airport { get; set; }

        public virtual void GetLandingPermission()
        {
            if (Airport != null)
            {
                bool hasPermissionForLanding = 
                       Airport.GiveLandingPermission(FlightCode);
                if (hasPermissionForLanding)
                    Console.WriteLine("Inis izni verildi.");
                else
                    Console.WriteLine("Inis izni verilmedi!");
            }
            else
                Console.WriteLine("Ucak kaydı yapılmamış. İniş   
                        izni yok!");
        }
    }
    /// <summary>
    /// Concrete Collague
    /// </summary>
    public class THYAirline: AirlineBase
    {
        public override void GetLandingPermission()
        {
            Console.WriteLine(FlightCode + " nolu THY ucağı   
             inis icin izin gonderdi.");
            base.GetLandingPermission();
        }
    }
    /// <summary>
    /// Concrete Collague
    /// </summary>
    public class PegasusAirline:AirlineBase
    {
        public override void GetLandingPermission()
        {
            Console.WriteLine(FlightCode + " nolu Pegasus ucağı   
                  inis icin izin gonderdi.");
            base.GetLandingPermission();
        }
    }

Çıktı:

C# Iterator Pattern Kullanımı - OOP Design Pattern

Iterator (tekrarlayıcı) tasarım deseni, behavior grubununa ait, nesne koleksyonlarının (list,array,queue) elemanlarını belirlenen kurallara göre elde edilmesini düzenleyen tasarım desenidir. dofactory.com a göre hemen hemen bütün uygulamalarda kullanılmaktadır.

Iterator (tekrarlayıcı) tasarım deseni, behavior grubununa ait, nesne koleksyonlarının (list,array,queue) elemanlarını belirlenen kurallara göre elde edilmesini düzenleyen tasarım desenidir. dofactory.com a göre hemen hemen bütün uygulamalarda kullanılmaktadır.



Koleksiyonlar nesne tabanlı dillerde sıkça kullandığımız yapıların başında geliyor. Iterator tasarım deseni koleksiyonunun array, queue, list olduğunun bilinmesine ihtiyaç duyumadan koleksiyon elemanları üzerinde işlem yapılabilmesini sağlar. Koleksiyon içerisindeki nesneleri örneğin foreach ile dönersek sırasıyla işleriz fakat öyle bir ihtiyacımız var ki nesneleri 3’er 3’er dönmemiz gerekiyor. Bunu iterator tasarım kalıbıyla gerçekleştirebiliriz.

Aynı zamanda kendi itaratorlerimizi yazabiliriz bu kalıpla. Örneğin bir tarih aralığı verildi bize biz bu tarih aralığındaki çalışma günlerini bulucaz. Bunu mesela for veya foreach ile yapamayız ama iterator tasarım kalıbını kullanarak günler üzerinde gezebiliriz.

Aggregate sınıfları koleksiyon barındıran ve bu koleksiyon ile iterator sınıfını oluşturan sınıflardı. Iterator sınıfları ise ileri geri gitme gibi işlemlerin yapıldığı sınıflardır.

Bu örneği şimdi koda dökelim:

UML Şeması:



Kod:

    /// <summary>
    /// Iterator Interface
    /// </summary>
    public interface IAbstractIterator
    {
        bool Next();
    }
/// <summary>
    /// Haftasonlarını itere edicek şekilde tasarlanmış iterator sınıfımız
    /// </summary>
    public class FreeWeekDayIterator: IAbstractIterator
    {
        protected DateTimeAggregate DateRange;
        protected DateTime Cursor;

        public FreeWeekDayIterator(DateTimeAggregate dateRange)
        {
            DateRange = dateRange;
            Cursor = DateRange.DateBegin;
        }

        public bool Next()
        {
            if (Cursor.DayOfWeek == DayOfWeek.Saturday 
                          || Cursor.DayOfWeek == DayOfWeek.Sunday)
            {
                int daysToAdd = 
                   Cursor.DayOfWeek == DayOfWeek.Saturday ? 1 : 6;
                Cursor = Cursor.AddDays(daysToAdd);
                if (Cursor < DateRange.DateEnd)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                int dayid = (int)Cursor.DayOfWeek;
                int daysToWeekend = 6 - dayid;
                Cursor = Cursor.AddDays(daysToWeekend);
                return true;
            }
        }

        public DateTime Current
        {
            get { return Cursor; }
        }
    }

    /// <summary>
    /// Iterator yaratacak olan Aggregate interface
    /// </summary>
    public interface IDateTimeAggregate
    {
        FreeWeekDayIterator CreateIterator
                   (DateTime dateBegin, DateTime dateEnd);
    }

    /// <summary>
    /// Koleksiyon barındıran ve bu koleksiyon ile iterator 
    /// sınıfını oluşturan Aggregate sınıfı
    /// </summary>
    public class DateTimeAggregate : IDateTimeAggregate
    {
        public DateTime DateBegin;
        public DateTime DateEnd;

        public FreeWeekDayIterator CreateIterator
                (DateTime dateBegin, DateTime dateEnd)
        {
            DateBegin = dateBegin;
            DateEnd = dateEnd;

            return new FreeWeekDayIterator(this);
        }
    }
Çıktı:



C# Interpreter Pattern Kullanımı - OOP Design Pattern

Interpreter tasarım deseni, behavior grubununa ait, belli bir düzen veya kurala bağlı olan metinlerin sayısal veya mantıksal olarak işlenmesi gereken durumlarda kullanılır. dofactory.com a göre kullanım oranı %20 civarındadır.




Dofactory.com’da roma rakamlarının sayısal karşılığını bulan programa yer verilmiş bu pattern’i çok güzel açıklıyor bakmanızı tavsiye ederim.

UML şemasından göreceğiniz gibi TerminalExpression ile NonterminalExpression isimli iki farklı Exrepssion tipi vardır. Roma rakamlarından yola çıkarsak Roma rakamlarındaki her bir harf TerminalExpression’dur. Roma rakamları ile 4 işlem yapmak isteseydik toplama, çarpma gibi ifadeler NonterinalExpression olacaktı. 


Biz örneğimizin basit olması için NonterminalExpression kullanmıyacağız. Çok kullanılan bir pattern olmadığı için örnek bulmakta zorlandım ama şöyle bir şey yapabiliriz. Örneğin bir entegrasyon çalışıyor ve bize “SIYSI” gibi bir string ifade geliyor. 

S = DEPARTMAN: SATIS DEPARTMANI, MALIYET:10
I = DEPARTMAN: INSAN KAYNAKLARI, MALIYET:20
Y = DEPARTMAN: YAZILIM, MALIYET:30

Bizden istenen ise bu stringi charlara bölüp gelen değerin şirkete maliyetini bulmamız. Bunu yapmak için Interpreter tasarım desenini kullanabiliriz.



Kod:

    // Context class
    public class Context
    {
        public string Formula { get; set; }
        public int TotalCost { get; set; }
    }
    // Expression
    public abstract class DepartmentExpression
    {
        public abstract void Interpret(Context context);
    }
    // TerminalExpression
    public class HRExpression:DepartmentExpression
    {
        public override void Interpret(Context context)
        {
            context.TotalCost += 20;
        }
    }
    // TerminalExpression
    public class SoftwareExpression:DepartmentExpression
    {
        public override void Interpret(Context context)
        {
            context.TotalCost += 30;
        }
    }
    // TerminalExpression
    public class SalesExpression : DepartmentExpression
    {
        public override void Interpret(Context context)
        {
            context.TotalCost += 30;
        }
    }
//Client
    class Program
    {
        static List<DepartmentExpression> CreateExpressionTree
            (string formula)
        {
            // Expression ağacı oluşturulur
            List<DepartmentExpression> tree = new List<DepartmentExpression>();

            foreach (char role in formula)
            {
                if (role == 'S')
                    tree.Add(new SalesExpression());
                else if (role == 'I')
                    tree.Add(new HRExpression());
                else if (role == 'Y')
                    tree.Add(new SoftwareExpression());
            }
            return tree;
        }

        static void RunExpression(Context context)
        {
            foreach (DepartmentExpression expression in CreateExpressionTree
                  (context.Formula))
            {
                // TerminalExpression tiplerine ait harf sembolleri 
                // buradaki metod çağrısındada gönderilebilir.
                expression.Interpret(context); 
            }
            Console.WriteLine("{0} için maliyet {1}"
                          , context.Formula, context.TotalCost);
        }

        static void Main(string[] args)
        {
            Context context = new Context { Formula = "SIYSI" };
            RunExpression(context);

            Console.ReadLine();
        }
    }
Çıktı:



C# Command Pattern Kullanımı - OOP Design Pattern

Command design pattern (komut tasarım deseni) behavior grubununa ait, işlemlerin nesne haline getirilip başka bir nesne(invoker) üzerinden tetiklendiği bir tasarım desenidir. Command tasarım deseninin dofactory.com a göre kullanım sıklığı 80% civarındadır.







Bu pattern’e örnek olarak olarak dofactory.com’da hesap makinası örneği verilmiş bu pattern’i anlatan en güzel örneklerden biri bence. Hesap makinası düşünün 10+5-2*5 gibi bir çok komut gireriz ve ardından hesapla butonuna basar hesaplatırız. Burda da invoker aynı görevi görüyor bu programı yazsaydık invoker içerisine ICommand nesneleri gönderecek ve bunları bir listede tutacaktık. Ardından hesapla tusuna basıldığında ise bu commandları işlem sırasına göre çıkarıp işleyecektik.

Şimdi daha basit bir örnek yapalım: ICommand tipinde bir sınıfımız olsun. Bu interface’ten türeyen UndoCommand ve RedoCommand sınıflarımız olsun. Bunu şöyle düşünebilirsiniz Ctrl+Z ve Ctrl+Y yapan bir program yazdığımızı düşünelim, programda yaptığımız tüm Undo ve Redo commandları bir listede tutulup en son siz çalış dediğinizde çalışıyor. Mesela bilgisayarınızın takıldığında yaptığınız işlemleri sırayla yaptığını görmüşsünüzdür buda ona bir örnek. Şimdi bu programı yazalım:


UML Diagramı:
Kod:

    /// <summary>
    /// Command Interface
    /// </summary>
    public interface ICommand
    {
        void Execute();
    }

    /// <summary>
    /// Concrete Command Class
    /// </summary>
    public class UndoCommand : ICommand
    {
        public void Execute()
        {
            Console.WriteLine("Undo command worked.");
        }
    }

    /// <summary>
    /// Concrete Command Class
    /// </summary>
    public class RedoCommand:ICommand
    {
        public void Execute()
        {
            Console.WriteLine("Redo command worked.");
        }
    }

    public class Invoker
    {
        private Stack<ICommand> commandList = new Stack<ICommand>();

        public void ExecuteAll()
        {
            while (commandList.Count > 0)
                commandList.Pop().Execute();
        }

        public void AddCommand(ICommand c)
        {
            commandList.Push(c);
        }
    }

        static void Main(string[] args)
        {
            Invoker invoker = new Invoker();
            invoker.AddCommand(new UndoCommand());
            invoker.AddCommand(new UndoCommand());
            invoker.AddCommand(new RedoCommand());

            invoker.ExecuteAll();

            Console.ReadLine();

        }
Çıktı:




Bu örneğimiz LIFO’ya bir örnekte oldu. Stack yapımıza en son giren komutumuzu ilk çalıştıracak şekilde programımızı tasarlamış olduk.




C# Flyweight Pattern Kullanımı - OOP Design Pattern



Flyweight tasarım deseni; structural tasarım grubuna ait, sık kullanılan nesnelerin bellek yönetimini kontrol etmek için kullanılan bir tasarım desenidir. Dofactory.com a göre kullanım sıklığı %20 civarındadır.



FlyWeight tasarım deseni bellek tüketimini optimize etmek amacıyla kullanıldığını söylemiştik. Bu desende havuz mantığı söz konusudur. Örneğin kullanıcının ekranda tıkladığı her x,y kordinatına çember çizen bir oyun yazdığımızı düşünelim. Her tık için bir circle nesnesi yaratırsak bellek inanılmaz şişecektir. Fakat bir circle nesnesi oluştursak ve kullanıcı tıkladığında bu nesnenin x,y kordinatını değiştirip ekrana yazarsak sadece 1 nesne yaratarak bu programı yazabiliriz. Bu tasarım kalıbında değerleri farklı olacak olan özelliklere extrinsic, aynı olan özelliklere ise intrinsic denir.

Bir örnek üzerinden tasarım desenimizi inceleyecek olursak örneğin ekran klavyesi programı yazdığımızı düşünelim. Burada her basılan harf için yeni nesne oluştursak belleğimiz şişecektir. Bunun yerine başta tüm harflerin nesnesini oluştursak basılan harfın koduyla gidip havuzdan bu nesneyi çeksek harf sayısı kadar nesne oluşturmamız bize yetecektir.

UML Diagram:



Kod:

    /// <summary>
    /// The 'Flyweight' abstract class
    /// </summary>
    public abstract class Character
    {
        //intrinsic
        protected char symbol;
        protected int keyKod;
        //extrinsic
        protected int pointIndex;
           
        public abstract void Display(int pointIndex);

    }

    /// <summary>
    /// A 'ConcreteFlyweight' class
    /// </summary>
    public class CharacterA:Character
    {
        public CharacterA()
        {
            this.symbol = 'A';
            this.keyKod = 1;
        }

        public override void Display(int pointIndex)
        {
            this.pointIndex = pointIndex;
            Console.WriteLine(this.symbol + " (pointIndex " + this.pointIndex + ")");
        }
    }

    /// <summary>
    /// Z 'ConcreteFlyweight' class
    /// </summary>
    public class CharacterB:Character
    {
        public CharacterB()
        {
            this.symbol = 'B';
            this.keyKod = 2;
        }

        public override void Display(int pointIndex)
        {
            this.pointIndex = pointIndex;
            Console.WriteLine(this.symbol + " (pointIndex " + this.pointIndex + ")");
        }
    }


    /// <summary>
    /// Z 'ConcreteFlyweight' class
    /// </summary>
    public class CharacterZ : Character
    {
        public CharacterZ()
        {
            this.symbol = 'Z';
            this.keyKod = 29;
        }

        public override void Display(int pointIndex)
        {
            this.pointIndex = pointIndex;
            Console.WriteLine(this.symbol + " (pointIndex " + this.pointIndex + ")");
        }
    }

    /// <summary>
    /// The 'FlyweightFactory' class
    /// </summary>
    public class CharacterFactory
    {
        private Dictionary<char, Character> _characters = new Dictionary<char, Character>();

        public Character GetCharacter(char key)
        {
            Character character = null;

            if (_characters.ContainsKey(key))
            {
                character = _characters[key];
            }

            else
            {
                switch (key)
                {
                    case 'A': character = new CharacterA(); break;
                    case 'B': character = new CharacterB(); break;
                    //...
                    case 'Z': character = new CharacterZ(); break;
                }
                _characters.Add(key, character);
            }

            return character;
        }

    }

        static void Main(string[] args)
        {
            // Build a document with text
            string document = "AAZZBBZB";
            char[] chars = document.ToCharArray();
            CharacterFactory factory = new CharacterFactory();

            // extrinsic state
            int pointSize = 10;
            // For each character use a flyweight object

            foreach (char c in chars)
            {
                pointSize++;
                Character character = factory.GetCharacter(c);
                character.Display(pointSize);
            }
            // Wait for user
            Console.ReadKey();
        }

Çıktı: