Strategy Ne Değildir
Strategy ana algoritmayı gerçekleştiren sınıftan kalıtım değildir! Bu anlayış tamamen yanlış.
Kalıtım varsa bunun ismi Template Method Örüntüsüdür. Strategy ana algoritmayı gerçekleştiren sınıfa takılan davranıştır. Açıklaması şöyle.
Strategy ile tanımlanan arayüze uygun, farklı davranışlar gerçekleştiren sınıflar yazılır. Ve bu sınıflar ana algoritmayı çağıran sınıfa takılırlar. Strategy sınıfları genellikle bir Factory aracılığıyla yaratılır.
Strategy ana algoritmayı gerçekleştiren sınıftan kalıtım değildir! Bu anlayış tamamen yanlış.
Kalıtım varsa bunun ismi Template Method Örüntüsüdür. Strategy ana algoritmayı gerçekleştiren sınıfa takılan davranıştır. Açıklaması şöyle.
Imagine you design a Cache. The cache can have options regardingStrategy Nedir
- eviction policy (LIFO, FIFO, LRU)
- expiration policy (after read, after write)
- maximum size (number of elements, memory usage)
Now imagine you want to let the user of your cache choose any of these options, and you use inheritance. You'll need 3 * 2 * 2 = 12 different classes:
- LifoAfterReadNumberOfElementsBasedCache,
- LifoAfterReadMemoryBasedCache,
- etc.
Each of the 4 LifoXxx classes will have to implement the same algorithm to implement the LIFO strategy. Same for the other ones.
Implement it with the strategy pattern instead of inheritance, and you'll have a single Cache class, and 7 strategy classes (one for each strategy), that you can combine however you want, and without code duplication.
Strategy ile tanımlanan arayüze uygun, farklı davranışlar gerçekleştiren sınıflar yazılır. Ve bu sınıflar ana algoritmayı çağıran sınıfa takılırlar. Strategy sınıfları genellikle bir Factory aracılığıyla yaratılır.
Stategy'lerin Parameterik Olması
Örnek
Elimizde şöyle bir kod olsun
Çözüm 1
Şöyle yaparız. Her strategy kendi değerini kelvin'e veya başka ortak bir değere çevirir. Ana sınıf bu değerden okur.
Şöyle yaparız. Belki de strategy kullanmaya gerek bile yoktur. Her sınıf kullandığı birimi bilir. Geri kalan her şey parametriktir :)
Örnek - Sadece Enum Kullanmak
Örnek
Elimizde şöyle bir kod olsun
public abstract class Temperature {
public abstract double convert(Temperature to) throws AbsoluteZeroException;
}
Bu sınıftan kalıtan şöyle alt sınıflar olsunpublic class Celsius extends Temperature {
@Override
public double convert(Temperature to) {
...
}
}
vepublic class Fahrenheit extends Temperature {
@Override
public double convert(Temperature to) throws AbsoluteZeroException {
...
}
}
Her strategy bir Temperature nesnesi alıyor ancak birimi belli değil.Çözüm 1
Şöyle yaparız. Her strategy kendi değerini kelvin'e veya başka ortak bir değere çevirir. Ana sınıf bu değerden okur.
public static Temperature convert(Temperature from, TemperatureScale to) {
double kelvin = from.toKelvin();
return to.fromKelvin(kelvin);
}
Çözüm 2Şöyle yaparız. Belki de strategy kullanmaya gerek bile yoktur. Her sınıf kullandığı birimi bilir. Geri kalan her şey parametriktir :)
Tempature celcius = new Tempature(98.6, TempatureType.CELSIUS);
Tempature fahrenheit = Tempature.convert(tempatureCels, TempatureType.FAHRENHEIT);
Enumeration ile Strategy ÜretmekÖrnek - Sadece Enum Kullanmak
Şöyle yaparız
public enum FileType {
EXCEL(".xlsx") {
@Override
public void download() {
}
},
CSV(".csv") {
@Override
public void download() {
}
},
private String suffix;
FileType(String suffix) {
this.suffix = suffix;
}
public String getSuffix() {
return suffix;
}
public abstract void download();
}
@GetMapping("/exportOrderRecords")
public void downloadFile(User user, HttpServletResponse response) {
...
String fileType = user.getFileType();
FileType type = FileType.valueOf(fileType);
if (type!=null) {
type.download();
} else {
FileType.CSV.download();
}
}
Örnek - EnumMap
Burada yine bir Strategy arayüzü var ve her strategy kalıtımı için de bir Enum var. Aşağıdaki gibi Strategy sınıfları olsun
public interface class IStrategy {
}
public class DistanceStrategy implements IStrategy {
}
public class PowerStrategy implements IStrategy {
}
Bu sınıflar stateless ise Java'da EnumMap başka dillerde ise herhangi bir Map veri yapısına önceden doldurulurlar ve istenilince döndürülürler
GoF - Strategy Örüntüsü - Functional Java yazısına taşıdım
enum DataPresenterStrategyType { DISTANCE, POWER }
static EnumMap<DataPresenterStrategyType, IStrategy> lookupStrategy = new EnumMap();
{
lookupStrategy.put(DISTANCE, new DistanceStrategy());
lookupStrategy.put(POWER, new PowerStrategy());
}
DataPresenterStrategy toStrategy(StrategyType type) {
return lookupStrategy.get(type);
}
Eğer sınıflar statefull ise her seferinde yeni bir nesne yaratmak gerekir. Bu durumda Java 8 ile gelen Supplier arayüzü kullanılabilir. Örnekte Supplier ile Method Expression kullanılıyor.enum DataPresenterStrategyType {
DISTANCE(DistanceStrategy::new), POWER(PowerStrategy::new);
private final Supplier<DataPresenterStrategy> constructor;
DataPresenterStrategyType(Supplier<DataPresenterStrategy> constructor){
this.constructor = constructor;
}
DataPresenterStrategy newStrategy() {
return constructor.get();
}
}
Strategy ve Functional ProgrammingGoF - Strategy Örüntüsü - Functional Java yazısına taşıdım
Strategy ve Dependency Injection
Aynı anda Etkin Birden Fazla Strategy'e Sahip Olmak
Normalde strategylerden sadece bir tanesi etkindir. Her strategy birbiriyle yer değiştirebilen nesne anlamına gelir. Bir nesneye farklı roller eklenebiliyorsa her role strategy demek yanlıştır. Nesneye bir çok rol çalışma zamanında eklenip çıkarılabilir. Bu durumda Decorator Örüntüsüne başvurmak gerekir.
Hiç yorum yok:
Yorum Gönder