Tasarım Desenleri Nedir, Neden Kullanılır?

Merhaba arkadaşlar, bu yazımda size nesneye dayalı programlamayla ilgili olarak önemli bir konu olan tasarım desenlerinden bahsedeceğim. Tasarım desenleri programlama dilinden bağımsızdır. Yazılım geliştirme sürecinde sürekli karşılaşılan problemlere yapılan denemeler sonucunda en uygun çözümler geliştirilmiş ve bunlara tasarım desenleri adı verilmiştir. Bazı özelliklerinden bahsedecek olursak:

  • Her şeyi yeni baştan oluşturmayı önlerler
  • Tekrar tekrar kullanılabilirler
  • Birlikte kullanılarak çok daha büyük problemlerin çözümünde kullanılabilirler
  • Sürekli gelişime açıktırlar

Tasarım desenleri 3 ana gruba ayrılır. Bunlar oluşturucu, yapısal ve davranışsal tasarım desenleridir. Oluşturucu tasarım desenleri, sınıfların en uygun ve verimli oluşturulma düzenleriyle ilgili tasarım desenleridir. Yapısal tasarım desenleri, sınıflar arasındaki ilişkilerin yönetilmesine yönelik tasarım desenleridir. Davranışsal tasarım desenleri ise, sınıfların birbiriyle nasıl haberleşmesi gerektiğine yönelik tasarım desenleridir.

Birkaç tasarım desenini kısaca açıklamaya çalışalım.

Singleton(Tekillik)

Bu tasarım deseni, bir sınıftan sadece bir tane nesne oluşturulması için kısıtlama sağlamaktadır. Aslında farkında olmadan kullandığımız bu tasarım desenine örnek vermek gerekirse, JSF ‘deki FacesContext.getCurrentInstance() söylenebilir.

Basitçe söylemek gerekirse, bu tasarım deseninde bir sınıfımızın olduğunu ve içerisinde de private static olarak kendisinden bir nesne tanımlandığını düşünelim. Bir static metot yardımıyla bu nesneyi döndüğümüzü düşünelim. Son olarak da boş bir protected kurucu tanımladığımızı düşünürsek, bu sınıftan soyut bir sınıf olmamasına rağmen yeni bir nesne oluşturamayız. Tek yol olarak tanımladığımız metotdan dönen static nesnedir.

Bunu örnek bir sınıfla pekiştirelim.

public class SingletonSinif {
    private static SingletonSinif instance = null;
    protected SingletonSinif () {
    }
    public static SingletonSinif getInstance() {
        if(instance == null) {
            instance = new SingletonSinif ();
        }
        return instance;
    }
}

Görüldüğü gibi bu sınıftan sadece bir nesne oluşturulabilmektedir.

Peki, neden bir sınıftan sadece bir nesne oluşturmamız gerekir, ne zaman kullanmamız gerekir. Açıkça söylemek gerekirse bu konuda verilecek örnekler kullanım alanının çok küçük bir parçası olacaktır. Şimdi şöyle düşünelim, projenizde kullanacağınız global değişkenler var ve bunlar sürekli erişime ve değişime açık olmalılar. Aynı zamanda da her yerden erişmeniz de gerekiyor. Ne de olsa global dedik. Şimdi bunun için en uygun çözüm singleton bir sınıf tanımlamaktır.

Umarım anlatmak istediğimi anlamışsınızdır.

Builder(Oluşturucu)

Bu tasarım deseni, bir sınıftan farklı özelliklere sahip nesneler üretilmesi için kolaylaştırılmış bir yol sunmaktadır. Bir sınıf tanımladığımızı düşünelim ve bu sınıfın farklı alt alanları için farklı tasarlanmış kurucu fonksiyonları olduğunu düşünelim. Şimdi her bir farklı durum için yeni bir kurucu tanımlamamız gerekiyor. Bu hem yorucu hem de kod okunabilirliğini azaltıyor. İşte bu durumda yardımımıza bu tasarım deseni koşmakta. Sadece tek bir kurucu kullanıyormuş gibi işimizi kolaylaştırıyor ve okunabilirliği arttırıyor.

Pekala, şimdi bu tasarım desenini yapısından bahsedelim. Bir sınıfımız var ve bu sınıfımızın alt alanları bulunmakta. İlk olarak içerisinde static bir iç sınıf tanımladığımızı düşünelim. İçerisinde de bizim farklı durumlarda sürekli değişen alt alanlarımız olsun. Bu alt alanların set metotlarını tanımlıyoruz. Daha sonra ana sınıfımız için bir kurucu tanımlayıp parametre olarak bu sınıftan bir nesne alıyoruz. Şimdi son olarak da iç sınıfımızda bir metot tanımlayıp döndürdüğü nesne olarak da yeni bir ana sınıfımızdan nesne gönderiyoruz. Parametre olarak da kendisini gönderiyor.

Bu açıklamanın havada kaldığını ve anlaşılmadığını biliyorum ancak örnek kodu inceledikten sonra anlayacağınıza eminim.

public static class Builder {
        private final double price;
        private String color, brand;
        private int year;
        private boolean isSecondHand;

        public Builder(double price) {
            this.price = price;
        }

        public Builder setColor(String color) {
            this.color = color;
            return this;
        }

        public Builder setBrand(String brand) {
            this.brand = brand;
            return this;
        }

        public Builder setYear(int year) {
            this.year = year;
            return this;
        }

        public Builder secondHand(boolean isSecondHand) {
            this.isSecondHand = isSecondHand;
            return this;
        }

        public Car build() {
            return new Car(this);
        }
    }

    private Car(Builder builder) {
        price = builder.price;
        brand = builder.brand;
        color = builder.color;
        isSecondHand = builder.isSecondHand;
        year = builder.year;
    }
}

Pekala, sanırım bu örnekte bir farklılık var, o da builder yani iç sınıfımızın kurucusunun parametre alması. Bunu şöyle açıklayabiliriz, değişmeyen alt alanlarınız varsa bu şekilde kurucuya parametre alarak gereksiz kod kalabalığından kurtulmamızı sağlıyor. Örnek kullanımına bakacak olursak:

Car myCar = new Car.Builder(1250.12)
        .setBrand(“Opel”)
        .secondHand(true)
        .setColor(“Black”)
        .setYear(1995)
        .build();

Bu sadece basit bir örnek, bunu geliştirmek ihtiyacınıza ve hayal gücünüze kalmış.

EOC(End Of Code)

Yorum bırakın

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.