Merhaba. Bu yazıda size Prototype Design Pattern nedir ve Java ile nasıl örneklenir bundan bahsedeceğim.

Öncelikle nasıl bir sorunumuz olduğuna bakalım.

Diyelim ki yazdığınız uygulamada business logic içerisinde öyle bir an geliyor ki sizin aynı değerlere sahip ve aynı tipte olan 2 objeye sahip olmanız ihtiyacı doğuyor. Bu durumda ne yapabiliriz? 1-) Mevcutta var olan objeyi yenisine atama yapabiliriz. Yani Obje yeniObje = mevcutObje; diyebiliriz fakat bu istediğimiz durum olmaz çünkü ikisinin de referansı aynı, birinde yapılan değişiklik diğerini de etkiler. 2-) Yeni objeyi sıfırdan oluşturup mevcut objenin değerlerini atayabiliriz. Ama burada da başka bir sorun çıkıyor. Private değişkenler ne olacak? Onlara erişemeyebilir ve dolayısı ile değerlerini alamayabiliriz.

Prototype design pattern bu 2 yöntemle de çözemediğimiz obje klonlama konusunda bize yardımcı oluyor.

Şimdi kodlama ile örnekleyelim.

Shape.java

package com.ilkaygunel;

public abstract class Shape {
	public int x;
	public int y;
	public String color;

	public Shape() {
	}

	public Shape(Shape target) {
		if (target != null) {
			this.x = target.x;
			this.y = target.y;
			this.color = target.color;
		}
	}

	public abstract Shape clone();

	@Override
	public boolean equals(Object object2) {
		if (!(object2 instanceof Shape))
			return false;
		Shape shape2 = (Shape) object2;
		return shape2.x == x && shape2.y == y && shape2.color.equals(color);
	}
}

Shape sınıfı bizim üst sınıf olarak kullanacağımız bir sınıf. Diğer sınıflarımızı Shape sınıfından kalıtacağız. Shape sınıfı içerisinde iki boyutlu şekillerin sahip olduğu x,y ve renk bilgilerini tutan değişkenler mevcut. Parametre alan yapılandırıcısı gelen parametredeki değerleri sınıftaki değişkenlere atıyor. abstract tipte bir clone metodu mevcut. Shape sınıfını kalıtan sınıflar bu metodu override edecek. equals metodu da önce obje tiplerine ardından da ojenin değerlerine bakarak iki objenin aynı olup olmadığına bakıyor.

Circle.java

package com.ilkaygunel;

public class Circle extends Shape {
    public int radius;

    public Circle() {
    }

    public Circle(Circle target) {
        super(target);
        if (target != null) {
            this.radius = target.radius;
        }
    }

    @Override
    public Shape clone() {
        return new Circle(this);
    }

    @Override
    public boolean equals(Object object2) {
        if (!(object2 instanceof Circle) || !super.equals(object2)) return false;
        Circle shape2 = (Circle) object2;
        return shape2.radius == radius;
    }
}

Circle sınıfımız Shape abstract sınıfını kalıtan bir sınıf. Shape’den gelen değişkenlerin yanında kendisine özel radius değişkeni mevcut. Parametreli ve parametresiz iki yapılandırıcısı mevcut. Parametreli yapılandırıcı önce Shape sınıfının yapılandırıcısını çağırarak Shape sınıfındaki değişkenleri dolduruyor ardından da radius değişkenini. Shape sınıfında abstract olarak tanımlanmış olan clone() metodunun override edildiğini görüyoruz. Bu metodun yaptığı işlem Circle sınıfının o anki halini parametreli yapılandırıcısına vererek yeni bir obje oluşturma işlemi. equals metodu da yine override edilen sınıf. Objenin Circle tipinde olup olmadğına ve Shape içindeki equals metodunun döneceği değere bakılıyor, ikisi de true dönerse radius kontrolü yapılıyor.

Rectangle.java

package com.ilkaygunel;

public class Rectangle extends Shape {
	public int width;
	public int height;

	public Rectangle() {
	}

	public Rectangle(Rectangle target) {
		super(target);
		if (target != null) {
			this.width = target.width;
			this.height = target.height;
		}
	}

	@Override
	public Shape clone() {
		return new Rectangle(this);
	}

	@Override
	public boolean equals(Object object2) {
		if (!(object2 instanceof Rectangle) || !super.equals(object2))
			return false;
		Rectangle shape2 = (Rectangle) object2;
		return shape2.width == width && shape2.height == height;
	}
}

Rectangle sınıfımız da Shape sınıfımızı kalıtıyor. Kendisine ait width ve height özellikleri var. Parametre alan yapılandırıcısı önce Shape sınıfının yapılandırıcısını çağırıyor, ardından da kendisine ait width ve height özelliklerini dolduruyor. Circle sınıfı gibi Rectangle sınıfı da clone() metodunu override ediyor ve sınıfın o anki halini parametre alan yapılandırıcıya geçirerek yeni bir Rectangle nesnesi oluşturuyor. equals metodu da obje tipi ve Shape içindeki equals ile kontrollerini yapıyor ve devamında width ve height kontrolleri ile eşitlik kontrolü yapıyor.

MainClass.java

package com.ilkaygunel;

import java.util.ArrayList;
import java.util.List;

public class MainClass {
    public static void main(String[] args) {
        List<Shape> shapes = new ArrayList<>();
        List<Shape> shapesCopy = new ArrayList<>();

        Circle circle = new Circle();
        circle.x = 10;
        circle.y = 20;
        circle.radius = 15;
        circle.color = "red";
        shapes.add(circle);

        Circle anotherCircle = (Circle) circle.clone();
        shapes.add(anotherCircle);

        Rectangle rectangle = new Rectangle();
        rectangle.width = 10;
        rectangle.height = 20;
        rectangle.color = "blue";
        shapes.add(rectangle);

        cloneAndCompare(shapes, shapesCopy);
    }

    private static void cloneAndCompare(List<Shape> shapes, List<Shape> shapesCopy) {
        for (Shape shape : shapes) {
            shapesCopy.add(shape.clone());
        }
        
        int shapesListSize = shapes.size();
        Shape lastElementInShapes = shapes.get(shapesListSize -1);
        shapes.add(lastElementInShapes);
        shapesCopy.add(lastElementInShapes);

        for (int i = 0; i < shapes.size(); i++) {
            if (shapes.get(i) != shapesCopy.get(i)) {
                System.out.println(i + ": Shapes are different objects");
                if (shapes.get(i).equals(shapesCopy.get(i))) {
                    System.out.println(i + ": And they are identical");
                } else {
                    System.out.println(i + ": But they are not identical");
                }
            } else {
                System.out.println(i + ": Shape objects are the same");
            }
        }
    }
}

MainClass sınıfımız içindeki main metot içerisinde shapes ve shapesCopy isminde 2 listemiz var. Birisi orjinal objeleri tutarken diğeri klonlanmış objeleri tutacak. new operatörü ile bir Circle objesi oluşturup x,y,radius ve color bilgilerini atıyoruz. Akabinde de shapes listesine ekliyoruz. Devam eden kısımda da circle objesi üzerinden clone metodunu çağırıyoruz ve bize orjinal circle objesi ile aynı değerlere sahip farklı bir obje dönüyor. Dönen yeni objeyi de shapes listesine ekliyoruz.

Rectangle sınıfından da bir obje üretip alanlarını dolduruyoruz ve shapes listesine ekliyoruz.

Main metodunun sonunda cloneAndCompare(…) metodunu çağırıyoruz. cloneAndCompare metodu çağırılmadan önce shapes listemizde 3 eleman var ve shapesCopy listemiz boş. cloneAndCompare metodu öncelikle shapes listesindeki elemanlar üzerinden clone metodunu çağırarak shapesCopy listesini dolduruyor. Ardından shapes listesinin son sırasındaki elemanı hem shapes listesine tekrar ekliyor hem de bu elemanı shapesCopy listesine ekliyor.

Devam eden kısımda ise for döngüsü içerisinde bir if-else yer alıyor. if şartı içerisinde bir != ifadesi görüyoruz. Bildiğimiz üzere Java’da != ifadesi referans tipleri üzerinde kullanılırsa bu bellek adres kontrolü anlamına gelir. Bu nedenle buradaki if kısmı objelerin aynı referans gözünü işaret edip etmediğine ve dolayısı ile aynı olup olmadığına bakar, else kısmında zaten objelerin aynı olduğuna dair bir mesaj yazdırılıyor.

if kısmının içerisinde ise önce objelerin farklı objeler olduğuna dair mesaj yazdırılıyor ve ardından objeler üzerinden equals çağırılarak objelerin aynı değerlere sahip olup olmadığına bakıyor. Burada Circle ve Rectangle’ın kendilerine ait equals metotları çalıştırılacak. Eğer değerler birbirini tutuyorsa aynı olduklarına dair mesaj yazdırılıyor, aksi takdirde aynı olmadıklarına dair mesaj yazdırılıyor.

Ekran Görüntüsü

Konsol çıktısında görebileceğimiz gibi listedeki ilk 3 eleman için farklı objeler oldukları fakat aynı değerleri içerdiklerine dair mesaj yazdırılıyor. Fakat son eleman için aynı olduğuna diar bir mesaj yazdırılmış çünkü iki listede de son elaman aynı bellek gözünü işaret ediyor.

Bu yazıda anlatacaklarım bu kadar arkadaşlar. Başka bir yazıda görüşene kadar sağlıcakla kalın.