Object Pool – Tasarım Kalıpları

Merhabalar, bu yazımda Object Pool (Nesne Havuzu) tasarım kalıbından bahsedeceğim. Evet, Java’da nasıl nesne yaratılır biliyoruz, hatta bi önceki yazımda eğer nesneyi oluşturmak çok maliyetli ise Prototype tasarım kalıbını kullanmıştık. Object Pool tasarım kalıbı da isminden de anlaşıldığı gibi, havuzdan nesne alacağız. Yani biz sistemden birden fazla nesneler yaratıp, daha sonra ihtiyaç duyduğumuz zaman eğer istediğimiz tipte nesne havuzda var ise var olanı dönecek yok ise yaratıp havuza atılacak. Örneğin DAO sınıfları. İleride DAO tasarım kalıbına da ayrıca geleceğim. Veritabanı işleriyle uğraşırken DAO tasarım kalıbını kullanırız ve bir DAO sınıfından bir nesne yarattığımız zaman direkt sınıftan oluşturmaktan ziyade bir havuz içerisinden isteriz ki, eğer zaten varolan bir nesne var ise onu dönsün. Böylelikle performans ve zaman kaybı yaşamayalım. Nesne havuzuna attığımız nesneler sistemin herhangi bir yerinden çağrılabilecek olan nesnelerdir. Şimdi örnek üzerinden gidelim.

Base bir Basket nesnemiz olacak.

Basket.java

public abstract class Basket {
    public String type() {
        return "Base Basket";
    }
}

İçinde type adında bir metodu var ve türünü bize söylüyor. Şimdi bu Basket sınıfını extend eden IronBasket olsun. Sisteme bir sürü sepet ekleyebiliriz.

IronBasket.java

public class IronBasket extends Basket {

    @Override
    public String type() {
        return "Iron Basket";
    }
}

Son olarak BasketSource isimli sınıfımızı yaratalım.

BasketSource.java

public class BasketSource {
    private static BasketSource source = new BasketSource();
    private Map<Class<? extends Basket> , Basket> poolMap = new HashMap<Class<? extends Basket>, Basket>();

    private BasketSource() {
    }


    public static Basket getBasket(Class<? extends Basket> clazz) throws IllegalAccessException, InstantiationException {
        Basket b = source.poolMap.get(clazz);
        if (b == null) {
            b = clazz.newInstance();
            source.poolMap.put(b.getClass(), b);
        }
        return b;
    }
}

Görüldüğü gibi BasketSource sınıfımızdan getBasket diyerek istediğimiz türde sepet alabiliriz. Sistemde eğer o sepet yoksa yaratılacak varsa da bize yaratılmış olan sepeti verecek.

Main.java

public class Main {

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Basket basket = BasketSource.getBasket(IronBasket.class);
        System.out.println(basket.type() + " " + basket.toString());
        Basket basket2 = BasketSource.getBasket(IronBasket.class);
        System.out.println(basket.type() + " " + basket.toString());
    }
}

Kodun çıktısına bakınca aynı nesneyi bize verdiğini görüyoruz. Object Pool tasarım kalıbı, kontrollü nesneler oluşturulmak istendiğinde, nesne sürecini hızlandırmak istendiğinde veya kullanılacak nesne sayısına sınırlama getirmek istendiğinde tercih edilebilir.

Bir yazının daha sonuna gelmiş olduk. 🙂

Prototype – Tasarım Kalıpları

Merhabalar, bu yazımda Prototype Tasarım kalıbını anlatmaya çalışacağım. Bir sistemde, bir yazılımda nesne oluşturma süreçleri çok önemlidir. Zaten tasarım kalıplarının kendi içinde neden 3’e ayrıldığını ve Oluşturucu Tasarım kalıplarıyla giriş yapıldığından anlayabilirsiniz. Neyse, hele ki bu oluşacak nesneler çeşitli sebeplerden dolayı, oluşturulması uzun sürüyorsa. Bu gibi durumlarda sürekli bu nesneye ihtiyaç duyduğumuzda yeniden oluşturmak yerine, mevcut nesnenin bir klonunu alıp, set metodları ile istenilen şekilde yapılandırılabilir. İşte bu klon bir prototip’dir. Kavram olarak son derece anlaşılır ve basit:)

Bir örnek üzerinden ilerleyelim. Bilgisayar yaratmanın uzun bir işlem olduğunu düşünelim ve Cloneable arayüzünü implemente eden bir ComputerPrototype sınıfımız olsun.

ComputerPrototype.java

public abstract class ComputerPrototype implements Cloneable{
    private int ramSize;
    private int graphicCardSize;
    private double cpu;

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public void showComputer() {
        System.out.println("Ram : " + getRamSize());
        System.out.println("Graphic Card : " + getGraphicCardSize());
        System.out.println("CPU : " + getCpu());
    }

    public int getRamSize() {
        return ramSize;
    }

    public void setRamSize(int ramSize) {
        this.ramSize = ramSize;
    }

    public int getGraphicCardSize() {
        return graphicCardSize;
    }

    public void setGraphicCardSize(int graphicCardSize) {
        this.graphicCardSize = graphicCardSize;
    }

    public double getCpu() {
        return cpu;
    }

    public void setCpu(double cpu) {
        this.cpu = cpu;
    }
}

Evet, basit olarak bu sınıfımızda ram, gpu ve cpu ile ilgili bilgiler set ediliyor. Burada önemli olan nokta clone metodur. Ardından Computer sınıfımızı oluşturalım. Bu sınıf ComputerPrototype’ı extend edecek.

Computer.java

public class Computer extends ComputerPrototype {

    public Computer(int ramSize, int gpuSize, double cpu) {
        setCpu(cpu);
        setGraphicCardSize(gpuSize);
        setRamSize(ramSize);
    }
}

Görüldüğü gibi parent’ının set metodları çağrılarak Computer oluşturuluyor. İstersek ComputerPrototype ‘ı extend eden farklı özelliklere sahip olan sınıflarda yaratabiliriz. Şimdi gelelim Main sınıfımıza.

Main.java

public class Main {

    public static void main(String[] args) throws CloneNotSupportedException {
        Computer computer = new Computer(8,2,2.2);
        computer.showComputer();

        Computer computer2 = (Computer) computer.clone();
        computer2.setGraphicCardSize(4);
        computer2.setCpu(3.0);
        computer2.showComputer();
    }
}

İlk olarak computer nesnesini yarattık ve özelliklerini gösterdik, ardından clone metodunu kullanarak computer2 nesnemize atadık, set metodlarıyla computer2 nesnemizi şekillendirdik ve özelliklerini showComputer metoduyla ekrana yazdırmış olduk. Basit anlamda Prototype Tasarım kalıbının kullanımı bu şekildedir.

Gerçek ve büyük sistemlerde bir nesnenin yaratma maliyeti çok yüksekse Prototype tercih edilebilir.

Bir yazının daha sonuna geldik böylece 🙂

 

Builder – Tasarım Kalıpları

Merhabalar, bu yazımda Oluşturucu Tasarım Kalıplarından Builder Tasarım Kalıbına değineceğim. Builder, nesne üretim sürecinde değişik parçalar birleştirilip istenilen tipte nesne oluşumunu amaçlamaktadır. Klasik olarak Java’da bir nesne oluşturmak istediğimizde aşağıdaki kod bloklarına benzer şekilde nesnemizi oluştururuz.

Person person = new Person();
Person person2 = new Person("Ufuk", "Halis", 25);

Görüldüğü gibi Person sınıfı 2 tane constructer’a sahip ve nesne oluşturmak istendiği zaman bu ikisinden birini tercih etmek zorundayız. Peki ya bu sınıfta sadece Ad ve Soyad geçecek biçimde nesne oluşturmak istersek, evet yolu basit gidip bu iki parametreli yeni constructer’ı Person sınfında yaratmak. Ancak gereksinimler iyice değiştiği zaman ne olacak, Ad-Yaş, Soyad-Yaş gibi. Person sınıfı constructer’dan geçilmeyecek 🙂 İşte builder bu durumda yardımımıza giriyor. Nesnemizi oluştururken sadece set etmek istediğimiz alanları ayarlıyoruz ve nesnemizi yaratıyoruz. Hem kodun okunuşu bakımından hem de esnekliği bakımından daha iyi bir hale gelmiş oluyor. Person sınıfımızı Builder pattern’e uygun olacak şekilde tasarlayalım.

Person.java

public class Person {
    private String firstName;
    private String lastName;
    private int age;
    private String address;
    private String telephone;

    public static class Builder {
        private Person person;

        public Builder() {
            person = new Person();
        }

        public Builder setAddress(String address) {
            person.address = address;
            return this;
        }

        public Builder setAge(int age) {
            person.age = age;
            return this;
        }

        public Builder setFirstName(String firstName) {
            person.firstName = firstName;
            return this;
        }

        public Builder setLastName(String lastName) {
            person.lastName = lastName;
            return this;
        }

        public Builder setTelephone(String telephone) {
            person.telephone = telephone;
            return this;
        }

        public Person build() {
            return person;
        }
    }

}

Main.java

public class Main {

    public static void main(String[] args) {
        Person person = new Person.Builder().
                        setFirstName("Ufuk").
                        setLastName("Halis").
                        setAge(25).build();
        Person person2 = new Person.Builder().build();
    }
}

Görüldüğü gibi Person sınıfında bir Builder sınıfı yarattık ve Person sınıfının sahip olduğu değerleri bu Builder sınıfı içerisinde set lemiş olduk. Person sınıfındaki tüm değerlerimiz optional bir bakıma, bazı durumlarda Builder ile bir nesne yaratmak istiyoruz ancak olmazsa olmaz başlangıç değerleri istiyorsak, bunuda Builder’ın constructer’ında yapabiliriz. Böylece o alanlar required hale gelir.

Builder Tasarım kalıbı, karmaşık nesne oluşturma süreçlerinden kurtararak değişik parametreler ile nesne oluşturmak istenildiğinde kullanılması tercih edilir.

Bir yazının daha sonuna gelmiş bulunuyoruz böylelikle 🙂

Factory – Tasarım Kalıpları

Merhabalar, bu yazımızda Factory tasarım kalıbına değineceğim. Evet isminden de anlaşılacağı gibi nesne üretmeye yarayan bu tasarım kalıbı, Yaratıcı Tasarım Kalıplarından en çok kullanılanlarından biridir.Factory ‘nin Abstract Factory , Factory Method, Builder gibi tasarım kalıplarıyla benzerlik gösterir. Örneğim Factory Method tasarım kalıbını kullanarak yapacağım.

Senaryomuz şöyle olacak, Factory sınıfına vereceğimiz tipe göre bize İşletim Sistemi nesnesini versin ve elimizdeki işletim sisteminin önce açıp sonra kapatalım. Öncelikle bir IOperatingSystem adında interface ‘imiz olacak ve bu sınıfın gövdesi olmayan metodları yer alacak.(Java 8 ile interface’lerde metodlara başında default anahtar kelimesini koyarak gövdesini yazabilirsiniz.) Daha sonra bu interface’imizi implemente eden gerçek işletim sistemi sınıfları olacak. OperatingSystemFactory sınıfı ile de vereceğimiz tipe göre işletim sistemimizi yaratacağız. Şimdi biraz kodları görelim 🙂

IOperatingSystem.java

public interface IOperatingSystem {

    void start();

    void shutdown();

    void writeOperatingSystemName();
}

Ardından işletim sistemi sınıflarımızı kodlayalım.

Ubuntu.java

public class Ubuntu implements IOperatingSystem {
    @Override
    public void start() {
        System.out.println("Ubuntu started!");
    }

    @Override
    public void shutdown() {
        System.out.println("Ubuntu shutdown!");
    }

    @Override
    public void writeOperatingSystemName() {
        System.out.println("Ubuntu - Linux is the best OS");
    }
}

Windows.java

public class Windows implements IOperatingSystem {
    @Override
    public void start() {
        System.out.println("Windows started!");
    }

    @Override
    public void shutdown() {
        System.out.println("Windows shutdown!");
    }

    @Override
    public void writeOperatingSystemName() {
        System.out.println("Windows");
    }
}

Ardından Factory sınıfımızı ekliyoruz.

OperatingSystemFactory.java

public class OperatingSystemFactory {

    public static IOperatingSystem create(final String type) {
        if (type.equals("UBUNTU")) {
            return new Ubuntu();
        } else if (type.equals("WINDOWS")) {
            return new Windows();
        } else {
            throw new RuntimeException("Operating System not found!");
        }
    }

}

Ve son olarak Main sınıfımızda İşletim Sınıfımızı yaratalım.

Main.java

import com.patterns.factorymethod.IOperatingSystem;
import com.patterns.factorymethod.OperatingSystemFactory;

public class Main {

    public static void main(String[] args) {
        IOperatingSystem operatingSystem = OperatingSystemFactory.create("UBUNTU");
        operatingSystem.start();
        operatingSystem.shutdown();
        operatingSystem.writeOperatingSystemName();
    }
}

Çıktı:
Ubuntu started!
Ubuntu shutdown!
Ubuntu – Linux is the best OS

Evet görüldüğü gibi Factory sınıfımıza tip vererek istediğimiz İşletim Sınıfı nesnemizi yarattık ve metotlarını kullandık. Artık kurduğumuz bu sisteme yeni bir İşletim Sınıfı eklemek daha kolay ve hızlı olacak.

Şimdilik bu kadar görüşmek üzere…

Bir fıkra hatırlıyorum. Adam doktora gider. Kederli olduğunu söyler. Hayat onun için zor ve zalimdir. Tehtitkâr bir dünyada kendini yapayanlız hissettiğini söyler. Doktor tedavisi basit der. Büyük palyaço Pagliacci şehrimize geldi. Git onu gör seni neşelendirir. Adam göz yaşlarına boğulur. Ama doktor der Pagliacci benim zaten.(Watchmen 2009)

Singleton – Tasarım Kalıpları

Merhaba, evet kendisi en çok kullanılan tasarım kalıbı sanırım. Elinizi attığınız her projede kullanılan bir kalıp. Singleton, Tekillik olarak çevrilebilir. Bu tasarım kalıbı, bir sınıftan sadece bir nesne oluşturulması ve bu nesnenin tüm sistemlerde kullanılması durumunda ihtiyaç duyulur. Şimdi bir Singleton örnek kodunu görelim.

Singleton.java

package com.patterns.singleton;

/**
 * Created by ufuk on 19.8.2016.
 */
public class Singleton {

    private static Singleton instance = null;
    private static Object lock = new Object();

    private Singleton() {
        //private constructor
    }

    public static Singleton instance() {
        if (instance == null) {
            synchronized (lock) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    public void println() {
        System.out.println(this);
    }
}

Örneği incelediğimizde bir Singleton sınıfında olması gerekenler:
1- Private bir constructor, böylece bu sınıftan new operatörü ile nesne oluşturulması önüne geçilir.
2- Sadece bir nesne oluşturulmasını istediğimiz için nesneyi static olarak tanımlama
3- Sadece bir nesne oluşturabilmek için static olarak tanımlanmış bir instance() metodu

Yukarıdaki kodda instance metodunda  synchronized kullanarak tek bir nesne oluşturulmasını garanti etmiş olduk. Bu double checking ‘in nedeni Java‘nın  multi threaded bir sistem olması durumu. Main sınıfımızda da for içinde instance metodunu 10 kere çağıralım.

Main.java

package com.patterns;

import com.patterns.singleton.Singleton;

public class Main {

    public static void main(String[] args) {
        for (int i=0; i<10; i++) {
            Singleton.instance().println();
        }
    }
}

Çıktı : 
com.patterns.singleton.Singleton@610455d6
com.patterns.singleton.Singleton@610455d6
com.patterns.singleton.Singleton@610455d6
com.patterns.singleton.Singleton@610455d6
com.patterns.singleton.Singleton@610455d6
com.patterns.singleton.Singleton@610455d6
com.patterns.singleton.Singleton@610455d6
com.patterns.singleton.Singleton@610455d6
com.patterns.singleton.Singleton@610455d6
com.patterns.singleton.Singleton@610455d6

Evet, görüldüğü gibi Singleton sınıfından sadece bir nesne oluştuğunu görebiliyoruz. Ancak Singleton tasarım kalıbının günümüzde Anti-Pattern durumu var. Bunun sebebi de sınıf constructor‘ının private olmasından dolayı, singleton nesnelerinin zor test edilmesinden dolayıdır.

Şimdilik bu kadar, görüşmek üzere…

O mükemmel değil. Sen de mükemmel değilsin. Asıl soru birbiriniz için mükemmel olup olmadığınız. (Good Will Hunting)