Giriş
Temelde iki çeşit Builder örüntüsü var
Temelde iki çeşit Builder örüntüsü var
1. Blind Builder : Ayrı bir sınıftır
2. Bloch Builder : Kullanılmak istenen sınıfın içine public static bir builder yazılır.
3. Functional Builder : Sınıfa bir şeyler eklemek için array of functions kullanılır
Blind Builder ve Bloch Builder'ın Ortak Özellikleri
Her iki Builder sınıfı da seçime bağlı özellikler için default değerler sağlamalıdır. Zorunlu parametreler zaten kullanıcı tarafından verilecektir.
Bu alanlar artık değişmeyecektir.
1. Blind Builder
Builder yarattığı nesneden ayrıdır. Yaratılan nesne ise içine Builder alan private bir constructor veya setter metodları tanımlar. Örnek
2. Bloch Builder
Bloch Builder, Effective Java kitabında gösteriliyor. Kullanılmak istenen sınıfın içine public static bir builder yerleştiriliyor. Yaratılan nesne ise içine Builder alan private bir constructor tanımlar.
Yukarıdaki örnekte Builder static ve nested bir sınıf. Kullanırken Pizza sınıfını yarattığı kolayca okunabilir.
3. Functional Builder
Blind Builder ve Bloch Builder'ın Ortak Özellikleri
Her iki Builder sınıfı da seçime bağlı özellikler için default değerler sağlamalıdır. Zorunlu parametreler zaten kullanıcı tarafından verilecektir.
class Builder {
private String builderColor = "white"; // default color
private String builderWheels = "round"; // default wheels
private int builderSpeed = 100; // default speed
}
Build Edilen Sınıf Zorunlu Parametreleri final YapmalıdırBu alanlar artık değişmeyecektir.
public class Car {
public static Builder builder() {
return new Builder();
}
// static inner class builder
public static class Builder {
...
}
// final (immutable) fields.
private final String color;
private final String wheels;
private final int speed;
// private constructor, only the builder calls this....
private Car(String color, String wheels, int speed) {
this.color = color;
this.wheels = wheels;
this.speed = speed;
}
}
1. Blind Builder
Builder yarattığı nesneden ayrıdır. Yaratılan nesne ise içine Builder alan private bir constructor veya setter metodları tanımlar. Örnek
class CarBuilder {
private String wheels;
private String color;
private int speed;
...
}
Bu Builder tüm zorunlu ve isteğe bağlı parametreleri içinde biriktirir. Daha sonra build metodu ile yeni bir nesne yaratır. Dolayısıyla build metodu aşağıdakine benzer.public Car build() {
// validate your attributes
Car car = new Car();
// set all attributes in your car
return car;
}
Eğer gerekirse build metodu içinde verinin doğruluğu da kontrol edilebilir.public Car build(){
// validate your values e.g.
if (speed < 25) {
throw new IllegalValueException("Car is too slow.");
}
// further validation
Car car = new Car();
car.setWheels(wheels);
car.setColor(color);
car.setSpeed(speed);
return car;
}
2. Bloch Builder
Bloch Builder, Effective Java kitabında gösteriliyor. Kullanılmak istenen sınıfın içine public static bir builder yerleştiriliyor. Yaratılan nesne ise içine Builder alan private bir constructor tanımlar.
Yukarıdaki örnekte Builder static ve nested bir sınıf. Kullanırken Pizza sınıfını yarattığı kolayca okunabilir.
Pizza pizza = new Pizza.Builder(12)
.cheese(true)
.pepperoni(true)
.bacon(true)
.build();
Örnek - Generics Kullanan Block Builder
Type parameters are not inherited from outer class to static nested class.
Bu yüzden şöyle yapmak gerekir
LanguageMatcher.Builder<MyClass, YourClass> lm =
new LanguageMatcher.Builder<MyClass, YourClass>();
Örnek
Ben şöyle yaptım
public class RemoteMapSourceParams<T, K, V> {
private final String mapName;
private final Predicate<K, V> predicate;
private final Projection<? super Map.Entry<K, V>, ? extends T> projection;
private RemoteMapSourceParams(Builder<T, K, V> builder) {
this.mapName = builder.mapName;
this.predicate = builder.predicate;
this.projection = builder.projection;
}
// Getters
public static <T, K, V> Builder<T, K, V> builder(String mapName) {
return new Builder<>(mapName);
}
public static class Builder<T, K, V> {
private final String mapName;
private String dataConnectionName;
private ClientConfig clientConfig;
private Predicate<K, V> predicate;
private Projection<? super Map.Entry<K, V>, ? extends T> projection;
public Builder(String mapName) {
Objects.requireNonNull(mapName, "mapName can not be null");
this.mapName = mapName;
}
//Setters
public RemoteMapSourceParams<T, K, V> build() {
return new RemoteMapSourceParams<>(this);
}
}
}
Örnek
Elimizde şöyle bir arayüz olsun
@FunctionalInterfaceinterface Coffee {List<String> ingredients();static Coffee withSaltedCaramelFudge(Coffee coffee) {return () -> coffee.add("Salted Caramel Fudge");}default List<String> add(String item) {return new ArrayList<>(ingredients()) {{add(item);}};}static Coffee withSweetenedMilk(Coffee coffee) {return () -> coffee.add("Sweetened Milk");}static Coffee withDarkCookieCrumb(Coffee coffee) {return () -> coffee.add("Dark Cookie Crumb");}static Coffee withVanillaAlmondExtract(Coffee coffee) {return () -> coffee.add("Vanilla/Almond Extract");}}
Builder olarak şu kodu kullanırız.
@SafeVarargsstatic Coffee getCoffeeWithExtra(Coffee coffee, Function<Coffee, Coffee>... ingredients) {var reduced = Stream.of(ingredients).reduce(Function.identity(), Function::andThen);return reduced.apply(coffee);}
Bu kodu kullanmak için şöyle yaparız
record CoffeeCup(List<String> initialIngredient) implements Coffee {@Overridepublic List<String> ingredients() {return initialIngredient;}}var ingredients = List.of("Tim Horton");var coffeeCup = new CoffeeCup(ingredients);var coffee = getCoffeeWithExtra(coffeeCup,Coffee::withDarkCookieCrumb,Coffee::withSaltedCaramelFudge,Coffee::withSweetenedMilk,Coffee::withVanillaAlmondExtract);System.out.println("Coffee with " + String.join(", ", coffee.ingredients()));}
Hiç yorum yok:
Yorum Gönder